feat(issues): issue-tracker-tools — create/update/list/get + Forgejo-inline-sync #117

Merged
janpeter merged 4 commits from feat/issue-tracker into main 2026-08-17 08:57:25 +02:00
Owner

Fase 6 van het issue-tracker-plan (docs/superpowers/plans/2026-08-16-issue-tracker.md in Scrum4Me; spec docs/superpowers/specs/2026-08-16-issue-tracker-design.md, beide dubbel-GO). Vier MCP-tools waarmee agents problemen op max2 en scrum4me-server kunnen registreren, onderzoeken en oplossen — met een spiegel naar Forgejo zodat het daar ook zichtbaar is.

Tools

create_issue — registreert een probleem als ISS-n. Met een stabiele fingerprint (<host>:<component>:<kern>) telt een herhaling op bij het bestaande open issue in plaats van een kopie te maken; is dat issue gesloten als FIXED of CANNOT_REPRODUCE, dan spreekt de nieuwe melding die conclusie tegen en heropent het als regressie. Bij WONT_FIX, DUPLICATE en INVALID gebeurt dat bewust niet — daar is de beslissing genomen. De partial unique index maakt dedup race-bestendig; de verliezer van een gelijktijdige insert vangt P2002 en valt eenmalig terug op het optel-pad.

update_issue — appendt aan onderzoek en oplossing in plaats van te overschrijven: meerdere agents werken na elkaar aan hetzelfde issue. Elke append krijgt een scheider met tijdstip en afzender, uit authored_by of anders de token-username — bewust nooit uit Issue.reported_by, want dat is de mélder. In de normale gang van zaken (max2 meldt, een andere agent onderzoekt) zou elke regel anders de verkeerde naam dragen, team-zichtbaar én gespiegeld.

list_issues / get_issue — lezen; gesloten issues blijven standaard buiten de lijst.

Spiegel

src/lib/issue-sync.ts draait hetzelfde algoritme als de web-executor: session-scoped advisory lock op een pooler-vrije verbinding (hij moet de HTTP-calls overspannen), render én CAS-snapshot uit één verse read ná de lock, boekhouding via de pg-client zodat updated_at onaangeraakt blijft. Zonder DIRECT_URL slaat de MCP inline-sync over in plaats van te forceren — forgejo_dirty blijft staan en de repair-sweep in Scrum4Me is het gegarandeerde pad.

Lockstep

Submodule vendor/scrum4me-shared op c63f0bd (scrum4me-shared #51 + #52). Scrum4Me bumpt naar dezelfde basis; de DB-migratie hoort bij die kant.

Verificatie

npm test groen: 190 testbestanden, 1419 tests, waarvan 32 nieuw (7 create, 8 update, 5 list/get, 12 sync). npm run typecheck groen.


🤖 Generated with Claude Code

Fase 6 van het issue-tracker-plan (`docs/superpowers/plans/2026-08-16-issue-tracker.md` in Scrum4Me; spec `docs/superpowers/specs/2026-08-16-issue-tracker-design.md`, beide dubbel-GO). Vier MCP-tools waarmee agents problemen op max2 en scrum4me-server kunnen registreren, onderzoeken en oplossen — met een spiegel naar Forgejo zodat het daar ook zichtbaar is. ## Tools **`create_issue`** — registreert een probleem als ISS-n. Met een stabiele `fingerprint` (`<host>:<component>:<kern>`) telt een herhaling op bij het bestaande open issue in plaats van een kopie te maken; is dat issue gesloten als FIXED of CANNOT_REPRODUCE, dan spreekt de nieuwe melding die conclusie tegen en heropent het als regressie. Bij WONT_FIX, DUPLICATE en INVALID gebeurt dat bewust niet — daar is de beslissing genomen. De partial unique index maakt dedup race-bestendig; de verliezer van een gelijktijdige insert vangt P2002 en valt eenmalig terug op het optel-pad. **`update_issue`** — appendt aan onderzoek en oplossing in plaats van te overschrijven: meerdere agents werken na elkaar aan hetzelfde issue. Elke append krijgt een scheider met tijdstip en afzender, uit `authored_by` of anders de token-username — bewust nooit uit `Issue.reported_by`, want dat is de mélder. In de normale gang van zaken (max2 meldt, een andere agent onderzoekt) zou elke regel anders de verkeerde naam dragen, team-zichtbaar én gespiegeld. **`list_issues` / `get_issue`** — lezen; gesloten issues blijven standaard buiten de lijst. ## Spiegel `src/lib/issue-sync.ts` draait hetzelfde algoritme als de web-executor: session-scoped advisory lock op een pooler-vrije verbinding (hij moet de HTTP-calls overspannen), render én CAS-snapshot uit één verse read ná de lock, boekhouding via de pg-client zodat `updated_at` onaangeraakt blijft. Zonder `DIRECT_URL` slaat de MCP inline-sync over in plaats van te forceren — `forgejo_dirty` blijft staan en de repair-sweep in Scrum4Me is het gegarandeerde pad. ## Lockstep Submodule `vendor/scrum4me-shared` op `c63f0bd` (scrum4me-shared #51 + #52). Scrum4Me bumpt naar dezelfde basis; de DB-migratie hoort bij die kant. ## Verificatie `npm test` groen: 190 testbestanden, 1419 tests, waarvan 32 nieuw (7 create, 8 update, 5 list/get, 12 sync). `npm run typecheck` groen. --- 🤖 Generated with [Claude Code](https://claude.com/claude-code)
De primaire melder van infra-problemen is een agent op max2 of
scrum4me-server, en die ziet hetzelfde symptoom vaak opnieuw. Zonder dedup
zou de tracker vollopen met kopieën.

Een stabiele fingerprint (<host>:<component>:<kern>) bindt meldingen aan
elkaar: bestaat er een open issue, dan telt de melding op in plaats van een
nieuw issue te maken. Is het issue gesloten als FIXED of CANNOT_REPRODUCE, dan
spreekt een nieuwe melding die conclusie tegen en heropent het als regressie.
Bij WONT_FIX, DUPLICATE of INVALID gebeurt dat bewust niet — daar is de
beslissing genomen en zegt een herhaling alleen iets over de frequentie.

De partial unique index maakt de dedup race-bestendig, maar dan moet de
verliezer van een gelijktijdige insert wel iets zinnigs doen: die vangt P2002
op en valt eenmalig terug op het optel-pad.

reported_by is een expliciet inputveld. De gedeelde toolset kent geen
caller-host-identiteit, dus zonder dat veld zou elk issue anoniem binnenkomen.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
update_issue appendt aan onderzoek en oplossing in plaats van te
overschrijven. Meerdere agents werken na elkaar aan hetzelfde issue; de
web-action mag vervangen omdat daar één mens aan het woord is, maar hier zou
overschrijven het spoor van een voorganger wissen.

Elke append krijgt een scheider met tijdstip en afzender. Die afzender komt
uit authored_by, of anders uit de token-username — bewust nooit uit
Issue.reported_by. Dat veld is de melder van het probleem, en in de normale
gang van zaken (max2 meldt, een andere agent onderzoekt) zou elke
onderzoeksregel dan de verkeerde naam dragen, zichtbaar voor het team én
gespiegeld naar Forgejo. authored_by weigert whitespace: die zou anders door
de fallback glippen en een scheider zonder naam opleveren.

list_issues laat gesloten issues standaard weg. Wie kijkt of een probleem al
bekend is, wil de open verzameling; historie is een expliciete vraag.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
feat(issues): Forgejo-issue-API, session-lock op DIRECT_URL en inline-sync
All checks were successful
CI / Verify (pull_request) Successful in 1m59s
72c1f78192
Spiegelt de issue-tracker vanuit de MCP naar Forgejo, met hetzelfde algoritme
als de web-executor — dezelfde volgorde, dezelfde uitkomsten, dezelfde
invarianten. Alleen de HTTP-laag en de lock-helper zijn repo-eigen.

De lock is session-scoped op een pooler-vrije verbinding, want hij moet de
HTTP-calls overspannen. Zonder DIRECT_URL slaat de MCP inline-sync over in
plaats van te forceren: forgejo_dirty blijft staan en de repair-sweep in
Scrum4Me pakt het op, dus er gaat niets verloren.

Render en CAS-snapshot komen uit één verse read ná de lock. De voorcontrole
ervoor leest bewust geen rendervelden — die bespaart alleen een lock voor
rijen die niets te spiegelen hebben.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
fix(issues): forgejo_error draagt geen upstream response-body meer
All checks were successful
CI / Verify (pull_request) Successful in 1m57s
cabac78c4d
Uit de security-review van spec §10, die precies deze vraag openliet.

ForgejoError neemt de response-body van Forgejo mee in zijn message — nuttig in
de MCP-log, maar forgejo_error is geen logveld: het reist over het gedeelde
NOTIFY-kanaal naar elke SSE-client met toegang tot het product en wordt in de
UI getoond. redactToken vervangt alleen de letterlijke tokenstring; al het
overige ging ongefilterd mee.

De web-executor bouwde zijn foutmelding al zelf en had dit probleem niet. Deze
kant schrijft nu dezelfde vorm: status en foutcode, zonder body.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
janpeter/scrum4me-mcp!117
No description provided.