Change SQI I F Reqs Conf. Graded
add-community-resolution-feedback 67 D 67 67 19 ● 2026-07-23
S6 S6 S5 S4 S4 S4 S3 S3 S3 S3 S3 S3 S3 S3 S3
add-event-kritisch-label 89 B 100 78 3 ● 2026-07-18
S1 Spec explicitly offered 'inaktiv styling OR omit the severity badge' for no-severity Events. Impl resolved the choice by omitting (SEVERITY_COLOR has no 'inaktiv' entry, so the badge renders nothing). Spec did its job by naming the choice.S3 Spec required 'reusing the signal badge's severity-driven colour' but was silent on the colour SOURCE. Impl inlined hex values (#ef4444/#f59e0b/#22c55e) in EventSeverityBadge rather than importing a shared token, so the signal/event colours are now two copies that can drift.
add-event-reject-retraction 88 B 100 75 6 ● 2026-07-18
S4 Proposal asserted the POST /reject endpoint default flips to 'candidate' as a clean change; it oversimplified — both existing frontend callers (CandidateCard reject-noise, ereignisse/[slug] delete) posted bodyless and relied on the old default='rejected'. Impl corrected by making both send explicit {to:'rejected'}, preserving their semantics. No human needed.S3 tasks.md 4.1 said 'append a curation-surface note, forward pointer not re-narration' but did not cite docs/adr/CLAUDE.md's append-discipline form. canon-warden flagged the custom-titled section above References as drift; impl self-fixed to a dated ## Postscript at file bottom (one gate round).S1 tasks.md 4.4 was explicitly conditional ('Update event-* architecture.md IF documented there'); impl introspected and found no architecture.md files exist (only spec.md), so the invariant/URN-allocation shape is carried by the delta specs the archive syncs. Resolved without a human.
add-geo-conditional-auto-approve 74 C 100 47 2 ● 2026-07-17
S3 Design said auto_approve_source_ids() stays booleans-only but was silent that the existing truthy check had to be tightened to `is True` so a string value never also counts as unconditional; impl resolved this alone to honor D2's partition.S3 Spec/design silent on the dry-run --json output shape for geo-gated skips; impl decided to keep the flat selected-list (no new geo_skipped key) to avoid breaking external consumers.S3 Design D2 discussed the two registry accessors but was silent that _SourceBase.auto_approve: bool in models.py would reject the string value 'bonn_located' at the Pydantic loader; impl surfaced it (task.blocked) and, after lead confirmed the delta spec's fail-closed intent, widened to bool|str. Surfaced as a lead round-trip only because of the dev-loop's artificial scope walls forbidding models.py edits; in a solo apply this is a silent gap-fill, not a stakeholder escalation — hence S3, not S6. The mechanical resolution (union, not Literal) was already dictated by the delta spec's ignore-unknown-values requirement.
refine-issue-category-street-granularity 100 A 100 100 1 ◐ 2026-07-16
add-rail-delay-aggregates 80 B 100 61 4 ● 2026-07-16
S3 S4 S2 S1
add-manual-collector 95 A 100 90 5 ● 2026-07-13
S3 Spec was silent on the collector's CLI name ('manual') vs its source id ('manual-ops') split, and that run.py's is_enabled(args.name, args.name) keys on the CLI name, not the source id. Impl self-resolved by mirroring the existing open311 precedent (yaml id 'anliegen-bonn' != CLI name 'open311'). No human, non-blocking.
2026-07-04-fix-event-model-item-guids-canon 100 A 100 100 1 ◐ 2026-07-12
S0 Landed diff (45726fa) matches the MODIFIED delta 1:1 — the three `LageItem.fingerprint` mislabels (field def + create scenario + update scenario) corrected to the guid-token wording exactly as the delta specced. Doc-only, no code/migration change, as designed. Remaining diff lines are incidental blank-line churn from `openspec archive` sync, not a spec divergence.
2026-07-09-add-non-autobahn-geometry 84 B 100 69 4 ● 2026-07-10
S1 Radverkehr route-matching spike returned 0 valid Overpass matches (counting stations are point sensors, not named routes). Impl took the design.md-named fallback (keep existing point geometry). Spec explicitly framed this as a spike with a pre-named fallback.S4 Spec's proposed News mechanism (spaCy NER + Nominatim, per bd-kto0 and task 3.2 'add Nominatim call site') was found wrong/oversimplified: heavy dep + would bypass the gazetteer NEIGHBOR_GEMEINDEN suppression. Impl corrected to an offline-gazetteer Point-upgrade, no human, no Nominatim call.S1 Amtlich WFS spike found no OGC WFS exists at stadtplan.bonn.de; impl took the design.md D4 static-Stadtbezirk-polygon fallback, already delivered via geo._apply. Spec named the fallback for this contingency.
2026-07-09-add-ereignisse-linked-data 94 A 100 87 7 ● 2026-07-10
S4 Spec (ADR-0003 D-1 / task 1.1) asserted eventStatus in the emitted allow-list, but it is not a defined term in either the lage or NGSI-LD core context and the Event model has no field/source for it. Impl corrected the interpretation: allow-list = MAY emit; eventStatus is never emitted today, so both the closed-allow-list and defined-term invariants hold. No human, no vocab change.
2026-07-09-baustellen-tagesaktuell 98 A 100 96 11 ● 2026-07-10
S3 Spec (task 3.1 'confirm/extend EndPoll purge handling') was silent on a concrete defect: consumers/base.py run_stdin only recognized NINA-shaped warningId:msgType guids, so feed-mode items (open311 and now baustelle) were rejected on the stdin path. Impl found and fixed this gap alone; no human, no rework round.
add-trusted-source-auto-approve 92 A 100 83 4 ● 2026-07-02
S1 Allow-list membership explicitly deferred to the operator at merge, with a recommended seed. impl resolved it via the documented recommendation; no human block, work completed.S3 Spec covered sources.schema.yaml docs + registry reader but was silent that the extra=forbid pydantic loader needs a matching field for the new auto_approve key. impl discovered and added it proactively (no verifier fail).
improve-correlation-precision 66 D 100 32 2 ● 2026-07-02
S4 S3 S1 S1 S1
add-event-membership-editing 95 A 100 90 20 ● 2026-06-23
S1 Spec explicitly deferred whether /review/ereignisse redirect is permanent or temporary (default: redirect now). Impl resolved autonomously to a 301 permanent redirect. No human.S1 Spec explicitly deferred whether split lets the curator choose event_category (default: derive default). Impl followed the derive-default path. No human.S4 Spec asserted the column be added to src/lage/models.py (LageItem model / items table mapping). The items table mapping actually lives in src/lage/store.py (_items sa.Table); impl added the column there and a DB-only drop in row->LageItem hydration. models.py was not touched. Spec location was wrong; corrected without a human.S3 Spec frontend Impact named only routes/admin/events, relocated review components, and TopNav. Impl additionally had to extend web/src/lib/eventStream.ts with a CurationItem interface and curation_locked field for the excluded-items view. Spec was silent; impl decided alone.
harden-openapi-contract 70 C 54 86 8 ● 2026-06-21
S7 Spec (proposal+design+tasks 2.4, via battle-test C2) asserted /api/events should model the AS-IS bare-array body and /api/events/{id} a flattened no-wrapper dict. Against current api.py this premise was false (api.py:674 already returns canon {items,total}; :796 returns {event,items,signals}); modelling the stale shape would have broken the task 3.2 schema-vs-body gate. Implementer journaled task.blocked ('Halting for artifact-update decision'); design.md + tasks.md were edited at apply to unblock. Spec defect halted impl until the spec changed.S3 Spec route enumeration was written against an older api.py and was silent on 5 live public routes that needed typed models: /api/radzaehlung/counts, /api/kpi/geo-coverage, /api/kpi/product, /api/events/urn/{slug}, /feed/allris.atom. Implementer discovered and added them to scope alone, no human.S3 Spec was silent on whether the curator-token-gated routes (GET /api/curation/events + 4 POST .../{confirm,recategorize,merge,reject}) belong in the public schema. Implementer decided to exclude them, extending the C6 precedent set for /api/versions, with no human.S1 Design Open Question explicitly deferred: shared ErrorResponse model vs per-route inline shape for /api/events/{id} 404. Spec named the unknown and told impl to resolve at task 2.4; impl resolved to one shared ErrorResponse via introspection, no human.
add-event-identification-ui 88 B 92 85 19 ● 2026-06-20
S2 server_default satisfies NOT NULL without separate backfillS3 spec silent on open_events excluding rejected (C-A1 leak fix)S3 spec silent on festival keyword match algorithmS4 tasks.md asserted router module contradicting monolith requirement; impl inlinedS3 spec silent on migrating pre-existing tests to confirmed-onlyS1 spec deferred generate-py OR load-at-import; impl resolved to load-at-importS5 one extra verifier FAIL round on dual-dialect migration task
add-event-correlation 91 A 91 91 16 ◐ 2026-06-16
S3 S5 S3 S3
open311-bonn-collector 61 — 61 5 ◐ 2026-06-15
S3 S3 S3 S1 S3 S2
add-vorlagen-party-filter 95 A 100 90 5 ◐ 2026-06-15
S3 Spec is internally inconsistent on the exact aria-live status string: the scenario/example text reads "Grüne · 7 von 23 Vorlagen" while design.md (D4) and tasks.md 2.4 show "{selected} · {visible.length} von {data.count}" with no trailing 'Vorlagen'. The implementer silently chose the shorter form (no 'Vorlagen' word) with no human input. Under-specified detail filled alone.
add-radzaehlung-source 89 B 100 78 6 ● 2026-06-15
S3 GeoJSON location fallback property names (bezeichnung, name) — spec said join on lage; impl added undocumented alternatives when lage is absentS3 CSV column name case variants (Lage, Wann_Datum, Anzahl_Raeder) — spec referenced lowercase column names; impl silently handled mixed-case CSV headersS3 Summary/title format strings — spec said conveys the hourly profile; impl chose format independently
add-provenance-invariant-gate 42 F 7 78 3 ● 2026-06-14T15:30:00Z
S7 task.blocked: original violation definition unimplementable — spec halted until lage-tlb shipped + full re-specS6 decision: user consulted to choose scope fork A/B/CS3 metrics-collection path unspecified; impl chose /api/status hookS1 alert for: window not specified; impl resolved to 5m
oepnv-per-bezirk-signals 89 B 100 78 4 ● 2026-06-13
S4 Spec asserted UI tests for the suppression scenarios; no component test framework exists in web/ and the scope wall forbids adding one. Impl substituted svelte-check type-verification of the HEALTHY_SUPPRESSED map structure, journalled the decision, and rewrote the task. Spec claim was oversimplified; resolved without a human.
add-issue-category-scheme 84 B 100 69 4 ● 2026-06-13
S3 Spec required byte-identical deterministic sync but was silent on how to model each mapping resource. Impl found blank nodes get fresh rdflib IDs each parse (non-deterministic .nt) and chose named IRIs (bonn:1.1 .. bonn:retired-gruenschnitt) alone, without a human. Gap the spec should have named.S4 Serving task asserted that registering both resources in registry.ts (plus verifying the index/content-negotiation) was the serving step. In this repo routing is per-resource: each served resource also needs its own SvelteKit +server.ts route handler, or the path 404s on every representation while still listing on the /lage index. Spec/task omitted the route-handler step; the build-only verifier never made an HTTP request so it false-passed. Corrected without escalation by adding the two route handlers and re-verifying over live HTTP.
add-allris-watcher-signal 89 B 100 78 1 ◐ 2026-06-12
S1 HTTP-200 HTML maintenance page parses as well-formed empty feed (bozo=False) -> watcher returns 'up'. Spec explicitly flagged this as verify-and-branch (design D2 'verified by the fixture, not assumed'; Risks documents residual false-up as accepted; tasks 5.2 conditional bead). Impl confirmed via fixture, xfail'd the test, filed lage-0i4. Resolved by introspection, no human, no rework loop.
add-allris-atom-feed 56 F 69 42 4 ● 2026-06-11
S4 /feed.atom renamed to /feed/current.atom — spec said combined /feed.atom route 'SHALL be unaffected' and scenario 'Combined feed is unchanged'; /atom alias kept, /feed.atom URL goneS4 proposal asserted 'k8s: none — no new workload, ingress' change; manifest/base/ingress.yaml required routing for /feed/*.atom (399eedf)S5 deploy fail->fix->fail->fix: first fix routed /feed/*.atom to api (399eedf), still broken because OpenShift drops pathType Exact, second fix to Prefix (f03c254) — 1 extra roundS3 HEAD handlers added for all feed routes — spec silentS3 /feed web index page (+page.svelte) + nav/footer links — spec silent on any web UIS3 scripts/check-feeds.py + scripts/openspec-journal.py — spec silent on operational helpers
nina-warn-signal 92 A 100 85 6 ◐ 2026-06-10
S4 Delta spec asserted the window cut-off 'SHALL be evaluated in the database query (NOW()-relative) for single-clock comparison'. Impl computes the cutoff client-side (effective_now - timedelta) and compares first_seen >= cutoff string. Built without a human; verifier passed. The single-clock/DB-side intent (lens F6) was the spec's assertion; impl simplified to a passed-now. Fidelity divergence the spec should be corrected to match (or impl hardened).
migrate-feed-pipeline-to-kafka 98 A 100 95 9 ◐ 2026-06-10
S1 design.md left 'one collector for all sources vs one Deployment per source-type' open. Impl resolved it via introspection — one feed-collector run_once iterating all due sources (collectors/feed.py). No human, no rework. The spec did its job by naming the unknown.S1 design.md D-3 left 'consumer re-tags vs trusts the producer tag' to decide in tasks. Impl resolved it — geo.tag_item + bonn_only applied at the producer (collectors/feed.py). Self-resolved, no human.
nina-collector 80 B 100 61 9 ● 2026-06-09
S4 Spec asserted wrong NINA API field names: payload.data[] (not info[]), languageCode (not language); effective treated as reliable (absent in practice). Impl discovered real shape from live API, self-corrected. Spec updated in-place during apply (write-back done).S4 Spec listed wrong geocodes: 051110000000 (Düsseldorf) and 053160000000 (Leverkusen) instead of 053140000000 (Bonn) and 053820000000 (Rhein-Sieg-Kreis). Impl fixed silently in commit e04ca4d. Archived spec still contains the wrong values — write-back NOT done.S3 Spec stated poll interval=60s default but was silent on CLI configurability. Impl added --interval flag and --once mode (needed for CronJob pattern). No human consulted.S3 Spec silent on observability. Impl added Prometheus /metrics HTTP endpoint and Kubernetes ServiceMonitor (commits 5338d0e, ba3239b). No mention in spec or tasks.S3 Spec silent on liveness mechanism. Impl added --heartbeat-path file-touch for Kubernetes livenessProbe (commit 7b6768f). Infra requirement not stated.S3 Spec silent on Kafka producer durability config. Impl explicitly sets acks=all on Producer to prevent silent drops on Cancel messages. Derived from operational reasoning, not the spec.S3 Spec said provision a KafkaTopic but was silent on the Strimzi bootstrap service name. Impl required lage-kafka-bootstrap (Strimzi naming convention), corrected in commit 7db82b3 after initial failure.