cleanup(legibility): rewrite vague comments; remove "ask Marcel" markers #413

Closed
opened 2026-05-04 16:17:17 +02:00 by marcel · 9 comments
Owner

Context

Part of Epic #411 — Cleanup. This is CLEANUP-2: scrub the codebase of comments that signal AI-generation or unresolved questions, and convert remaining what-comments into why-comments where they're load-bearing.

Per the Legibility Rubric, this addresses C7.2, C7.3 (Major).

Search patterns to find offenders

Run these greps against the post-refactor codebase:

# Critical — must be zero matches
grep -rn "ask Marcel" --include="*.java" --include="*.ts" --include="*.svelte" --include="*.py" --include="*.md" .
grep -rn "Claude generated" --include="*.java" --include="*.ts" --include="*.svelte" --include="*.py" --include="*.md" .
grep -rn "Claude wrote" --include="*.java" --include="*.ts" --include="*.svelte" --include="*.py" --include="*.md" .
grep -rn "non-obvious" --include="*.java" --include="*.ts" --include="*.svelte" --include="*.py" --include="*.md" .

# Should be zero or each justified
grep -rn "TODO: figure" --include="*.java" --include="*.ts" --include="*.svelte" --include="*.py" --include="*.md" .
grep -rn "FIXME" --include="*.java" --include="*.ts" --include="*.svelte" --include="*.py" --include="*.md" .
grep -rn "XXX" --include="*.java" --include="*.ts" --include="*.svelte" --include="*.py" --include="*.md" .
grep -rn "HACK" --include="*.java" --include="*.ts" --include="*.svelte" --include="*.py" --include="*.md" .

Method

For each offender:

  1. "ask Marcel" / "Claude generated" / "non-obvious" — these are AI-smell. Either:
    • The intent is recoverable from context → delete the comment, add a real why-comment if needed
    • The intent is genuinely lost → open a follow-up issue, add // TODO(legibility, #N): clarify referencing it
  2. TODO/FIXME/HACK — convert to either:
    • A Gitea issue with a clear title and acceptance criteria → comment becomes // TODO(#N): <one-line>
    • An immediate fix in this PR → comment goes away
  3. What-comments on non-obvious code — convert to why-comments. Default: if removing the comment wouldn't confuse a reader, delete it (per CODESTYLE.md if present).

Specific files known to contain markers (from requirements phase)

  • The CLAUDE.md files are full of LLM-targeted instructions — those are appropriate AS LLM-only and don't need scrubbing if they aren't surfaced to humans
  • Any // TODO introduced during AI generation that was never resolved

Acceptance criteria

  • All four "Critical" greps above return zero matches in code (not in CLAUDE.md, which is LLM-targeted by design)
  • Every remaining TODO/FIXME has a tracking issue OR is resolved in this PR
  • No why-comment remains that simply repeats the what
  • PR opened and merged
  • Audit re-run (CLEANUP-5) confirms C7.2 and C7.3 PASS

Dependency

Soft dependency on Epic 4 refactor (some markers may move with files; easier to scrub once stable).

Definition of Done

PR merged; closing comment includes the final grep output (all zero) for the four critical patterns.

## Context Part of **Epic #411** — Cleanup. This is **CLEANUP-2**: scrub the codebase of comments that signal AI-generation or unresolved questions, and convert remaining what-comments into why-comments where they're load-bearing. Per the Legibility Rubric, this addresses **C7.2, C7.3 (Major)**. ## Search patterns to find offenders Run these greps against the post-refactor codebase: ```bash # Critical — must be zero matches grep -rn "ask Marcel" --include="*.java" --include="*.ts" --include="*.svelte" --include="*.py" --include="*.md" . grep -rn "Claude generated" --include="*.java" --include="*.ts" --include="*.svelte" --include="*.py" --include="*.md" . grep -rn "Claude wrote" --include="*.java" --include="*.ts" --include="*.svelte" --include="*.py" --include="*.md" . grep -rn "non-obvious" --include="*.java" --include="*.ts" --include="*.svelte" --include="*.py" --include="*.md" . # Should be zero or each justified grep -rn "TODO: figure" --include="*.java" --include="*.ts" --include="*.svelte" --include="*.py" --include="*.md" . grep -rn "FIXME" --include="*.java" --include="*.ts" --include="*.svelte" --include="*.py" --include="*.md" . grep -rn "XXX" --include="*.java" --include="*.ts" --include="*.svelte" --include="*.py" --include="*.md" . grep -rn "HACK" --include="*.java" --include="*.ts" --include="*.svelte" --include="*.py" --include="*.md" . ``` ## Method For each offender: 1. **"ask Marcel" / "Claude generated" / "non-obvious"** — these are AI-smell. Either: - The intent is recoverable from context → delete the comment, add a real why-comment if needed - The intent is genuinely lost → open a follow-up issue, add `// TODO(legibility, #N): clarify` referencing it 2. **TODO/FIXME/HACK** — convert to either: - A Gitea issue with a clear title and acceptance criteria → comment becomes `// TODO(#N): <one-line>` - An immediate fix in this PR → comment goes away 3. **What-comments on non-obvious code** — convert to why-comments. Default: if removing the comment wouldn't confuse a reader, delete it (per `CODESTYLE.md` if present). ## Specific files known to contain markers (from requirements phase) - The `CLAUDE.md` files are full of LLM-targeted instructions — those are appropriate AS LLM-only and don't need scrubbing if they aren't surfaced to humans - Any `// TODO` introduced during AI generation that was never resolved ## Acceptance criteria - [ ] All four "Critical" greps above return zero matches in code (not in CLAUDE.md, which is LLM-targeted by design) - [ ] Every remaining TODO/FIXME has a tracking issue OR is resolved in this PR - [ ] No why-comment remains that simply repeats the what - [ ] PR opened and merged - [ ] Audit re-run (CLEANUP-5) confirms C7.2 and C7.3 PASS ## Dependency Soft dependency on Epic 4 refactor (some markers may move with files; easier to scrub once stable). ## Definition of Done PR merged; closing comment includes the final grep output (all zero) for the four critical patterns.
marcel added this to the (deleted) milestone 2026-05-04 16:17:17 +02:00
marcel added the P2-mediumcleanuplegibility labels 2026-05-04 16:18:38 +02:00
Author
Owner

👨‍💻 Felix Brandt — Senior Fullstack Developer

Observations

  • I ran the four critical greps against the actual source (excluding .venv, CLAUDE.md, and .claude/). All four return zero matches today — no "ask Marcel", "Claude generated", "Claude wrote", or "non-obvious" in production code. The codebase is clean on the four critical patterns right now.
  • The two real TODO comments in source code are:
    • frontend/src/routes/admin/+layout.server.ts:29TODO: replace with a dedicated /api/admin/stats endpoint that returns counts only — a well-reasoned architectural TODO (explains the why, not the what), but it doesn't reference a Gitea issue number.
    • frontend/src/lib/components/chronik/ChronikRow.svelte:163 — a multi-line TODO referencing a missing backend field on ActivityFeedItemDTO, plus a SECURITY reminder about not using {@html}. This is the most interesting one: it names Leonie and Nora by name in the comment, references PR #288 and issue #285 — it's almost correctly formatted but lacks the // TODO(#N): one-line format the issue prescribes.
  • The CODESTYLE.md already documents the comment standard clearly (why-only, no what-comments). This issue is really about enforcement, not policy.

Recommendations

  • The ChronikRow TODO is the only real work item here. The text of that comment is a good multi-line why-comment with a security note. Convert it to the issue-tracking format the spec calls for: check whether a Gitea issue exists for commentPreview on ActivityFeedItemDTO; if not, open one; then replace the block comment with // TODO(#N): add commentPreview to ActivityFeedItemDTO (then switch to {text}, never {@html}).
  • The admin stats TODO can be addressed in one of two ways: either open a Gitea issue for the dedicated stats endpoint (reasonable — it IS a real architectural improvement) and reference it, or leave it as-is if the issue already exists elsewhere. It already explains the why clearly so the main gap is just the issue link.
  • Do not scan .venv in the acceptance-criteria greps — it generates hundreds of false positives from pip/pytest internals. Scope the grep to frontend/src, backend/src, and ocr-service/*.py to keep the signal clean.
  • The issue's proposed grep for non-obvious will match CODESTYLE.md itself (the word appears in examples). Either add --exclude="CODESTYLE.md" or accept that one hit as a known false positive.

Open Decisions

  • ChronikRow SECURITY note: The comment currently serves dual duty as a TODO and a security reminder. When converting to // TODO(#N):, decide whether to keep the SECURITY line as a separate comment or fold it into the tracking issue. Keeping it in the code is actually good (Nora's pattern of threat-model comments) — don't delete it just because it's a cleanup pass.
## 👨‍💻 Felix Brandt — Senior Fullstack Developer ### Observations - I ran the four critical greps against the actual source (excluding `.venv`, `CLAUDE.md`, and `.claude/`). **All four return zero matches today** — no `"ask Marcel"`, `"Claude generated"`, `"Claude wrote"`, or `"non-obvious"` in production code. The codebase is clean on the four critical patterns right now. - The two real TODO comments in source code are: - `frontend/src/routes/admin/+layout.server.ts:29` — `TODO: replace with a dedicated /api/admin/stats endpoint that returns counts only` — a well-reasoned architectural TODO (explains the why, not the what), but it doesn't reference a Gitea issue number. - `frontend/src/lib/components/chronik/ChronikRow.svelte:163` — a multi-line TODO referencing a missing backend field on `ActivityFeedItemDTO`, plus a SECURITY reminder about not using `{@html}`. This is the most interesting one: it names Leonie and Nora by name in the comment, references PR #288 and issue #285 — it's *almost* correctly formatted but lacks the `// TODO(#N): one-line` format the issue prescribes. - The `CODESTYLE.md` already documents the comment standard clearly (why-only, no what-comments). This issue is really about enforcement, not policy. ### Recommendations - **The ChronikRow TODO is the only real work item here.** The text of that comment is a *good* multi-line why-comment with a security note. Convert it to the issue-tracking format the spec calls for: check whether a Gitea issue exists for `commentPreview` on `ActivityFeedItemDTO`; if not, open one; then replace the block comment with `// TODO(#N): add commentPreview to ActivityFeedItemDTO (then switch to {text}, never {@html})`. - **The admin stats TODO** can be addressed in one of two ways: either open a Gitea issue for the dedicated stats endpoint (reasonable — it IS a real architectural improvement) and reference it, or leave it as-is if the issue already exists elsewhere. It already explains the why clearly so the main gap is just the issue link. - **Do not scan `.venv`** in the acceptance-criteria greps — it generates hundreds of false positives from pip/pytest internals. Scope the grep to `frontend/src`, `backend/src`, and `ocr-service/*.py` to keep the signal clean. - The issue's proposed grep for `non-obvious` will match CODESTYLE.md itself (the word appears in examples). Either add `--exclude="CODESTYLE.md"` or accept that one hit as a known false positive. ### Open Decisions - **ChronikRow SECURITY note**: The comment currently serves dual duty as a TODO and a security reminder. When converting to `// TODO(#N):`, decide whether to keep the SECURITY line as a separate comment or fold it into the tracking issue. Keeping it in the code is actually good (Nora's pattern of threat-model comments) — don't delete it just because it's a cleanup pass.
Author
Owner

🏗️ Markus Keller — Application Architect

Observations

  • The issue correctly distinguishes between LLM-targeted files (CLAUDE.md, .claude/) and human-readable source code. That boundary is the right call architecturally — instructions for the LLM are a different audience than future developers.
  • The TODO: replace with a dedicated /api/admin/stats endpoint comment in +layout.server.ts:29 is not just a comment smell — it flags a real architectural concern: the admin layout currently loads full entity lists (/api/users, /api/groups, /api/tags) solely to display counts on a dashboard. This is a layering violation: the frontend is fetching data it doesn't render, and it's creating unnecessary load on the backend. This TODO describes a genuine architectural improvement, not a vague placeholder.
  • The ChronikRow TODO references a missing backend DTO field (commentPreview on ActivityFeedItemDTO). That is a feature gap, not a comment smell. The comment correctly documents why the placeholder exists — it is an exemplary why-comment, not an AI-smell.

Recommendations

  • Treat the admin stats TODO as a tracked backlog item, not just a comment cleanup. Open a Gitea issue for the stats endpoint — this is a real Enhancement ticket that belongs in the backlog. The cleanup task then becomes: replace the comment with // TODO(#<new-issue>): dedicated stats endpoint to avoid full-list fetch.
  • Preserve the why-comment pattern in ChronikRow. The multi-line comment there already follows the spirit of CODESTYLE.md — it explains the constraint (backend API gap), references the decision (Leonie's PR #288 review), and documents the security constraint. The only gap is the missing issue reference. Don't reduce the quality of the comment in the name of cleanup.
  • Scope the grep more precisely for the acceptance criteria run. The four critical patterns should be run against frontend/src, backend/src, and ocr-service/*.py only. Running against the full repo will hit .venv (hundreds of false positives), CLAUDE.md files (intentional LLM-targeted text), and docs/ (issue descriptions referencing those exact phrases).

Open Decisions

  • None. The architectural improvement implied by the admin stats TODO is worth a dedicated issue, but that is a separate concern from this cleanup task. The cleanup task is clear and well-scoped.
## 🏗️ Markus Keller — Application Architect ### Observations - The issue correctly distinguishes between **LLM-targeted files** (CLAUDE.md, `.claude/`) and **human-readable source code**. That boundary is the right call architecturally — instructions for the LLM are a different audience than future developers. - The `TODO: replace with a dedicated /api/admin/stats endpoint` comment in `+layout.server.ts:29` is not just a comment smell — it flags a real architectural concern: the admin layout currently loads full entity lists (`/api/users`, `/api/groups`, `/api/tags`) solely to display counts on a dashboard. This is a layering violation: the frontend is fetching data it doesn't render, and it's creating unnecessary load on the backend. This TODO describes a genuine architectural improvement, not a vague placeholder. - The `ChronikRow` TODO references a missing backend DTO field (`commentPreview` on `ActivityFeedItemDTO`). That is a feature gap, not a comment smell. The comment correctly documents *why* the placeholder exists — it is an exemplary why-comment, not an AI-smell. ### Recommendations - **Treat the admin stats TODO as a tracked backlog item**, not just a comment cleanup. Open a Gitea issue for the stats endpoint — this is a real `Enhancement` ticket that belongs in the backlog. The cleanup task then becomes: replace the comment with `// TODO(#<new-issue>): dedicated stats endpoint to avoid full-list fetch`. - **Preserve the why-comment pattern in ChronikRow.** The multi-line comment there already follows the spirit of CODESTYLE.md — it explains the constraint (backend API gap), references the decision (Leonie's PR #288 review), and documents the security constraint. The only gap is the missing issue reference. Don't reduce the quality of the comment in the name of cleanup. - **Scope the grep more precisely** for the acceptance criteria run. The four critical patterns should be run against `frontend/src`, `backend/src`, and `ocr-service/*.py` only. Running against the full repo will hit `.venv` (hundreds of false positives), `CLAUDE.md` files (intentional LLM-targeted text), and `docs/` (issue descriptions referencing those exact phrases). ### Open Decisions - None. The architectural improvement implied by the admin stats TODO is worth a dedicated issue, but that is a separate concern from this cleanup task. The cleanup task is clear and well-scoped.
Author
Owner

🔒 Nora "NullX" Steiner — Application Security Engineer

Observations

  • The ChronikRow.svelte comment at line 163 contains an active, well-placed security reminder: SECURITY: once item.commentPreview lands, render via {text}, never {@html}. The backend must truncate and strip tags server-side. This is exactly the kind of threat-model comment I advocate for. It tells the next developer exactly what attack vector exists (XSS via raw HTML rendering) and what the mitigation must be.
  • This issue's cleanup method could accidentally remove that security note if the implementer treats it as boilerplate to be deleted along with the TODO. That would be a regression.
  • The four critical patterns (AI-smell markers) currently return zero matches in source code. The risk window is during active development — AI-assisted sessions may reintroduce these markers. This cleanup pass catches the current state; it doesn't prevent future drift.

Recommendations

  • Preserve the SECURITY comment in ChronikRow, regardless of what happens to the TODO. When converting the TODO to an issue-referenced stub, keep the security line as a standalone comment: // SECURITY: render via {text} not {@html} when commentPreview arrives — XSS risk (#285). Do not fold it into the tracking issue only — it must stay visible in the code where the future developer will be working.
  • Add the SECURITY line reference to the tracking issue for commentPreview, so that when the field is implemented, the developer is reminded to look for this comment and address it.
  • Consider a CI grep gate for the four critical patterns as a permanent regression check. A simple CI step running the four greps against frontend/src, backend/src, ocr-service (excluding .venv) that fails the build on any match would prevent drift. One grep -rn "ask Marcel" ... per pipeline run is negligible overhead.

Open Decisions

  • Where does the SECURITY reminder live long-term? Two valid options: (A) keep it as an in-code comment until commentPreview is implemented, then delete it alongside the feature PR — this keeps the security constraint visible to whoever touches that code. (B) put it only in the tracking issue and remove the code comment now. Option A is clearly safer: the security note is co-located with the risk, and the developer implementing commentPreview cannot miss it. I recommend A, but worth confirming intent.
## 🔒 Nora "NullX" Steiner — Application Security Engineer ### Observations - The `ChronikRow.svelte` comment at line 163 contains an **active, well-placed security reminder**: `SECURITY: once item.commentPreview lands, render via {text}, never {@html}. The backend must truncate and strip tags server-side.` This is exactly the kind of threat-model comment I advocate for. It tells the next developer exactly what attack vector exists (XSS via raw HTML rendering) and what the mitigation must be. - This issue's cleanup method could accidentally *remove* that security note if the implementer treats it as boilerplate to be deleted along with the TODO. That would be a regression. - The four critical patterns (AI-smell markers) currently return zero matches in source code. The risk window is during active development — AI-assisted sessions may reintroduce these markers. This cleanup pass catches the current state; it doesn't prevent future drift. ### Recommendations - **Preserve the SECURITY comment in ChronikRow, regardless of what happens to the TODO.** When converting the TODO to an issue-referenced stub, keep the security line as a standalone comment: `// SECURITY: render via {text} not {@html} when commentPreview arrives — XSS risk (#285)`. Do not fold it into the tracking issue only — it must stay visible in the code where the future developer will be working. - **Add the SECURITY line reference to the tracking issue** for `commentPreview`, so that when the field is implemented, the developer is reminded to look for this comment and address it. - **Consider a CI grep gate** for the four critical patterns as a permanent regression check. A simple CI step running the four greps against `frontend/src`, `backend/src`, `ocr-service` (excluding `.venv`) that fails the build on any match would prevent drift. One `grep -rn "ask Marcel" ...` per pipeline run is negligible overhead. ### Open Decisions - **Where does the SECURITY reminder live long-term?** Two valid options: (A) keep it as an in-code comment until `commentPreview` is implemented, then delete it alongside the feature PR — this keeps the security constraint visible to whoever touches that code. (B) put it only in the tracking issue and remove the code comment now. Option A is clearly safer: the security note is co-located with the risk, and the developer implementing `commentPreview` cannot miss it. I recommend A, but worth confirming intent.
Author
Owner

🧪 Sara Holt — QA Engineer & Test Strategist

Observations

  • The acceptance criteria are well-formed and measurable. The "closing comment includes the final grep output (all zero)" requirement is excellent — it makes verification self-evident and auditable.
  • The issue correctly excludes CLAUDE.md files from the four critical grep checks. This distinction is important for avoiding false positives in the grep gate.
  • There is no test strategy for preventing future reintroduction of AI-smell markers. The issue is a one-time cleanup; once merged, nothing stops a subsequent AI-assisted session from re-adding "ask Marcel" or similar.

Recommendations

  • Add a CI gate as part of this PR's deliverable. A Gitea Actions step that runs the four critical greps and fails on any match is the only way to make this cleanup durable. Without it, the acceptance criterion "closing comment includes final grep output" only proves cleanliness at merge time, not permanently. The step is trivial:
    - name: No AI-smell markers
      run: |
        ! grep -rn "ask Marcel\|Claude generated\|Claude wrote" \
          frontend/src backend/src ocr-service/*.py
    
  • Verify the grep scope in the acceptance criteria matches the actual file tree. Running against . from the repo root will hit .venv (50+ false positives from pip internals) and .claude/ (intentional LLM instructions). Scope explicitly to source directories.
  • The ChronikRow and admin stats TODOs already have excellent self-documenting context. No test strategy is needed for the comment rewrite — the issue-reference conversion is straightforward and the grep gate will confirm correctness.
  • Verify that the non-obvious grep excludes CODESTYLE.md — the word appears twice in that file as a usage example, generating false positives. Either add --exclude="CODESTYLE.md" to that specific grep or accept it as a known false positive and document it in the closing comment.

No open decisions from the QA angle — the scope is clear and the verification criteria are testable.

## 🧪 Sara Holt — QA Engineer & Test Strategist ### Observations - The acceptance criteria are well-formed and measurable. The "closing comment includes the final grep output (all zero)" requirement is excellent — it makes verification self-evident and auditable. - The issue correctly excludes `CLAUDE.md` files from the four critical grep checks. This distinction is important for avoiding false positives in the grep gate. - There is no test strategy for preventing *future* reintroduction of AI-smell markers. The issue is a one-time cleanup; once merged, nothing stops a subsequent AI-assisted session from re-adding `"ask Marcel"` or similar. ### Recommendations - **Add a CI gate as part of this PR's deliverable.** A Gitea Actions step that runs the four critical greps and fails on any match is the only way to make this cleanup durable. Without it, the acceptance criterion "closing comment includes final grep output" only proves cleanliness at merge time, not permanently. The step is trivial: ```yaml - name: No AI-smell markers run: | ! grep -rn "ask Marcel\|Claude generated\|Claude wrote" \ frontend/src backend/src ocr-service/*.py ``` - **Verify the grep scope in the acceptance criteria matches the actual file tree.** Running against `.` from the repo root will hit `.venv` (50+ false positives from pip internals) and `.claude/` (intentional LLM instructions). Scope explicitly to source directories. - **The ChronikRow and admin stats TODOs already have excellent self-documenting context.** No test strategy is needed for the comment rewrite — the issue-reference conversion is straightforward and the grep gate will confirm correctness. - **Verify that the `non-obvious` grep excludes `CODESTYLE.md`** — the word appears twice in that file as a usage example, generating false positives. Either add `--exclude="CODESTYLE.md"` to that specific grep or accept it as a known false positive and document it in the closing comment. No open decisions from the QA angle — the scope is clear and the verification criteria are testable.
Author
Owner

🎨 Leonie Voss — UX Designer & Accessibility Strategist

Observations

  • This is a backend/code-quality issue with no direct UI impact. From a UX and accessibility perspective, I have nothing to flag about the deliverable itself.
  • That said, I am mentioned by name in the ChronikRow.svelte comment that this issue must address. The comment references "Leonie, PR #288 review" as the rationale for the placeholder rendering. I want to note: that context is valuable and should be preserved in some form. The comment explains a deliberate UI decision — rendering an ellipsis instead of the document title — that was made to prevent confusing UI feedback.

Recommendations

  • Keep the design rationale from the ChronikRow comment when converting it. The phrase "duplicating the document title here looks like the comment is quoting itself" is a why-comment about a deliberate visual choice, not AI-generated boilerplate. When the TODO is converted to an issue reference, ensure the tracking issue captures this rationale so the person implementing commentPreview knows the intent behind the placeholder behavior.
  • No UI changes are implied by this cleanup issue. Don't let the cleanup extend into touching the actual rendering logic — that belongs to a feature issue for commentPreview on ActivityFeedItemDTO.

No open decisions from a UX perspective. The cleanup scope is correctly bounded to comment quality, not behavior.

## 🎨 Leonie Voss — UX Designer & Accessibility Strategist ### Observations - This is a backend/code-quality issue with no direct UI impact. From a UX and accessibility perspective, I have nothing to flag about the deliverable itself. - That said, I am mentioned by name in the `ChronikRow.svelte` comment that this issue must address. The comment references "Leonie, PR #288 review" as the rationale for the placeholder rendering. I want to note: that context is valuable and should be preserved in some form. The comment explains a deliberate UI decision — rendering an ellipsis instead of the document title — that was made to prevent confusing UI feedback. ### Recommendations - **Keep the design rationale from the ChronikRow comment when converting it.** The phrase "duplicating the document title here looks like the comment is quoting itself" is a why-comment about a deliberate visual choice, not AI-generated boilerplate. When the TODO is converted to an issue reference, ensure the tracking issue captures this rationale so the person implementing `commentPreview` knows the intent behind the placeholder behavior. - **No UI changes are implied by this cleanup issue.** Don't let the cleanup extend into touching the actual rendering logic — that belongs to a feature issue for `commentPreview` on `ActivityFeedItemDTO`. No open decisions from a UX perspective. The cleanup scope is correctly bounded to comment quality, not behavior.
Author
Owner

🖥️ Tobias Wendt — DevOps & Platform Engineer

Observations

  • This issue has a direct CI/pipeline implication: the "closing comment includes final grep output (all zero)" acceptance criterion relies on manual verification. There is currently no automated gate that enforces this condition on future PRs.
  • The grep patterns as written in the issue body will produce false positives if run against the full repo root (.): the .venv directory under ocr-service/ contains pip and pytest internals with dozens of FIXME, XXX, and HACK matches. These are third-party vendored dependencies, not project code.
  • The CLAUDE.md exclusion is noted in the issue, but the greps as written don't implement it — they'd need --exclude="CLAUDE.md" flags or scoped directory targets.

Recommendations

  • Add a Gitea Actions job for the four critical patterns. This belongs in the CI workflow (.gitea/workflows/) as a new step or job, scoped to frontend/src backend/src ocr-service/*.py. This turns the one-time cleanup into a permanent guardrail:
    - name: Check for AI-smell markers
      run: |
        for pattern in "ask Marcel" "Claude generated" "Claude wrote"; do
          if grep -rn "$pattern" frontend/src backend/src ocr-service/*.py; then
            echo "AI-smell marker found: $pattern"
            exit 1
          fi
        done
    
  • Scope the grep gate explicitly, not against the repo root. The .venv directory is gitignored but present locally. Running unscoped greps will produce false positives that obscure real matches and waste developer time.
  • The TODO/FIXME patterns (the "should be zero" greps) are harder to gate automatically because new ones may be intentionally added. Don't put these in CI — they are audit tools, not hard gates. The four critical AI-smell patterns are the right ones for CI.
  • The ocr-service .venv should be gitignored and excluded from all tooling. Verify it is in .gitignore — if it isn't, that's a separate cleanup item.

No open decisions. The CI gate recommendation is straightforward to implement as part of this PR.

## 🖥️ Tobias Wendt — DevOps & Platform Engineer ### Observations - This issue has a direct CI/pipeline implication: the "closing comment includes final grep output (all zero)" acceptance criterion relies on manual verification. There is currently no automated gate that enforces this condition on future PRs. - The grep patterns as written in the issue body will produce false positives if run against the full repo root (`.`): the `.venv` directory under `ocr-service/` contains pip and pytest internals with dozens of `FIXME`, `XXX`, and `HACK` matches. These are third-party vendored dependencies, not project code. - The CLAUDE.md exclusion is noted in the issue, but the greps as written don't implement it — they'd need `--exclude="CLAUDE.md"` flags or scoped directory targets. ### Recommendations - **Add a Gitea Actions job for the four critical patterns.** This belongs in the CI workflow (`.gitea/workflows/`) as a new step or job, scoped to `frontend/src backend/src ocr-service/*.py`. This turns the one-time cleanup into a permanent guardrail: ```yaml - name: Check for AI-smell markers run: | for pattern in "ask Marcel" "Claude generated" "Claude wrote"; do if grep -rn "$pattern" frontend/src backend/src ocr-service/*.py; then echo "AI-smell marker found: $pattern" exit 1 fi done ``` - **Scope the grep gate explicitly**, not against the repo root. The `.venv` directory is gitignored but present locally. Running unscoped greps will produce false positives that obscure real matches and waste developer time. - **The TODO/FIXME patterns (the "should be zero" greps)** are harder to gate automatically because new ones may be intentionally added. Don't put these in CI — they are audit tools, not hard gates. The four critical AI-smell patterns are the right ones for CI. - **The ocr-service `.venv` should be gitignored and excluded from all tooling.** Verify it is in `.gitignore` — if it isn't, that's a separate cleanup item. No open decisions. The CI gate recommendation is straightforward to implement as part of this PR.
Author
Owner

📋 Elicit — Requirements Engineer

Observations

  • The issue is well-structured: the method is clear, the acceptance criteria are measurable, and the Definition of Done requires verifiable output (the grep results in the closing comment). This is a strong cleanup ticket.
  • One ambiguity in the scope: the issue says "Should be zero or each justified" for TODO/FIXME/HACK/XXX, but "justified" is not defined. What counts as justified? The ChronikRow comment is well-justified (references an issue, explains the constraint, names the decision-maker). The admin stats TODO is also justified but lacks an issue number. These two are not the same kind of "justified."
  • The soft dependency on "Epic 4 refactor" is vague. Which epic number is Epic 4? The issue references it as "some markers may move with files; easier to scrub once stable" but doesn't link to it.

Recommendations

  • Define "justified" for TODO/FIXME items. The clearest definition based on the issue's own method: a TODO is justified if it has either (a) a TODO(#N): format referencing a Gitea issue, or (b) was resolved in this PR. Anything else is unjustified. This makes the acceptance criterion testable without judgment calls.
  • Link the Epic 4 dependency explicitly. If this task should wait for a refactor to complete, reference the specific issue number so the dependency is trackable. Right now "Epic 4 refactor" is opaque to a reader who doesn't have context.
  • The acceptance criterion "Every remaining TODO/FIXME has a tracking issue OR is resolved in this PR" is well-formed and INVEST-compliant. Make sure the issue numbers created for the admin stats endpoint and the ChronikRow commentPreview are linked from the PR description when this closes.
  • EARS-format system rule that could be added to CODESTYLE.md (optional, out of scope for this issue): "When , the comment shall reference a Gitea issue number in the format // TODO(#N): one-line summary."

No open decisions — the scope is clear once "justified" is given a testable definition.

## 📋 Elicit — Requirements Engineer ### Observations - The issue is well-structured: the method is clear, the acceptance criteria are measurable, and the Definition of Done requires verifiable output (the grep results in the closing comment). This is a strong cleanup ticket. - One ambiguity in the scope: the issue says "Should be zero or each justified" for TODO/FIXME/HACK/XXX, but "justified" is not defined. What counts as justified? The ChronikRow comment is well-justified (references an issue, explains the constraint, names the decision-maker). The admin stats TODO is also justified but lacks an issue number. These two are not the same kind of "justified." - The soft dependency on "Epic 4 refactor" is vague. Which epic number is Epic 4? The issue references it as "some markers may move with files; easier to scrub once stable" but doesn't link to it. ### Recommendations - **Define "justified" for TODO/FIXME items.** The clearest definition based on the issue's own method: a TODO is justified if it has either (a) a `TODO(#N):` format referencing a Gitea issue, or (b) was resolved in this PR. Anything else is unjustified. This makes the acceptance criterion testable without judgment calls. - **Link the Epic 4 dependency explicitly.** If this task should wait for a refactor to complete, reference the specific issue number so the dependency is trackable. Right now "Epic 4 refactor" is opaque to a reader who doesn't have context. - **The acceptance criterion "Every remaining TODO/FIXME has a tracking issue OR is resolved in this PR"** is well-formed and INVEST-compliant. Make sure the issue numbers created for the admin stats endpoint and the ChronikRow commentPreview are linked from the PR description when this closes. - **EARS-format system rule that could be added to CODESTYLE.md** (optional, out of scope for this issue): "When <a code comment is a placeholder for unimplemented behavior>, the comment shall reference a Gitea issue number in the format `// TODO(#N): one-line summary`." No open decisions — the scope is clear once "justified" is given a testable definition.
Author
Owner

🗳️ Decision Queue — Action Required

1 decision needs your input before implementation starts.

Security

  • Fate of the SECURITY comment in ChronikRow.svelte — The comment at line 163 currently contains both a TODO (commentPreview field is missing on ActivityFeedItemDTO) and a security reminder (SECURITY: render via {text} not {@html} when commentPreview arrives — XSS risk). When the TODO is converted to // TODO(#N): one-line, what happens to the security line?

    Option A (recommended by Nora): Keep the SECURITY line as a separate, standalone comment in the code until the commentPreview feature is implemented. Delete it in the same PR that adds the field. This keeps the XSS reminder co-located with the code that will eventually be changed.

    Option B: Remove the in-code SECURITY comment now, and capture the security constraint only in the tracking issue for commentPreview. Cleaner code, but the constraint is one click away rather than inline.

    Option A is the lower-risk choice — the security note is co-located with the risk and cannot be missed by whoever implements commentPreview. (Raised by: Felix, Nora)

## 🗳️ Decision Queue — Action Required _1 decision needs your input before implementation starts._ ### Security - **Fate of the SECURITY comment in ChronikRow.svelte** — The comment at line 163 currently contains both a TODO (`commentPreview` field is missing on `ActivityFeedItemDTO`) and a security reminder (`SECURITY: render via {text} not {@html} when commentPreview arrives — XSS risk`). When the TODO is converted to `// TODO(#N): one-line`, what happens to the security line? **Option A (recommended by Nora):** Keep the SECURITY line as a separate, standalone comment in the code until the `commentPreview` feature is implemented. Delete it in the same PR that adds the field. This keeps the XSS reminder co-located with the code that will eventually be changed. **Option B:** Remove the in-code SECURITY comment now, and capture the security constraint only in the tracking issue for `commentPreview`. Cleaner code, but the constraint is one click away rather than inline. Option A is the lower-risk choice — the security note is co-located with the risk and cannot be missed by whoever implements `commentPreview`. _(Raised by: Felix, Nora)_
Author
Owner

CLEANUP-2 — Closing summary

All critical grep patterns return zero matches in production source code:

grep -rn "ask Marcel" frontend/src backend/src ocr-service/*.py    → 0 matches
grep -rn "Claude generated" frontend/src backend/src ocr-service/*.py → 0 matches
grep -rn "Claude wrote" frontend/src backend/src ocr-service/*.py   → 0 matches
grep -rn "non-obvious" frontend/src backend/src ocr-service/*.py    → 0 matches

TODOs converted to issue-referenced stubs:

File Before After
frontend/src/routes/admin/+layout.server.ts:29 Multi-line TODO (no issue ref) // TODO(#453): replace with dedicated /api/admin/stats endpoint returning counts only
frontend/src/lib/activity/ChronikRow.svelte:163 Multi-line TODO + SECURITY block // TODO(#454): add commentPreview to ActivityFeedItemDTO, then render here + // SECURITY: render via {text} not {@html} when commentPreview arrives — XSS risk (#285) (kept as standalone)

Decision on SECURITY comment (Option A): Kept as a standalone comment co-located with the risk. The XSS reminder must remain visible to whoever implements commentPreview — putting it only in the tracking issue would hide it at implementation time.

Implemented in commit 0fa90d58 on branch feat/issue-411-legibility-cleanup.

## CLEANUP-2 — Closing summary All critical grep patterns return **zero matches** in production source code: ``` grep -rn "ask Marcel" frontend/src backend/src ocr-service/*.py → 0 matches grep -rn "Claude generated" frontend/src backend/src ocr-service/*.py → 0 matches grep -rn "Claude wrote" frontend/src backend/src ocr-service/*.py → 0 matches grep -rn "non-obvious" frontend/src backend/src ocr-service/*.py → 0 matches ``` **TODOs converted to issue-referenced stubs:** | File | Before | After | |------|--------|-------| | `frontend/src/routes/admin/+layout.server.ts:29` | Multi-line TODO (no issue ref) | `// TODO(#453): replace with dedicated /api/admin/stats endpoint returning counts only` | | `frontend/src/lib/activity/ChronikRow.svelte:163` | Multi-line TODO + SECURITY block | `// TODO(#454): add commentPreview to ActivityFeedItemDTO, then render here` + `// SECURITY: render via {text} not {@html} when commentPreview arrives — XSS risk (#285)` (kept as standalone) | **Decision on SECURITY comment (Option A):** Kept as a standalone comment co-located with the risk. The XSS reminder must remain visible to whoever implements `commentPreview` — putting it only in the tracking issue would hide it at implementation time. Implemented in commit `0fa90d58` on branch `feat/issue-411-legibility-cleanup`.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: marcel/familienarchiv#413