mirror of
https://github.com/zvx-echo6/meshai.git
synced 2026-08-26 17:31:34 +00:00
docs: add B13 guard-ordering defect + session-2 reorder requirement + Amendment A2
- B13: cooldown/dedup armed before region/severity/matrix checks, causing below-threshold events to burn dedup slots and suppress future deliveries - Session 2 requirement: move cooldown commit and dedup record to after delivery decision to prevent matrix-only semantics from inheriting the trap - Amendment A2: document layout-aware append-only write fix with post-write verification (shared detect_config_layout helper, backup restore on failure) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
14916bdf3e
commit
8a30a2aef7
1 changed files with 38 additions and 0 deletions
|
|
@ -81,6 +81,7 @@ Every item re-checked against source.
|
||||||
| B10 | **Two mesh formatting regimes.** Legacy: LLM-summarize >200 chars. Toggle: deterministic composer, 150-byte budget. Same radio, different text rules. | router.py:187-193 vs composer.py:31 |
|
| B10 | **Two mesh formatting regimes.** Legacy: LLM-summarize >200 chars. Toggle: deterministic composer, 150-byte budget. Same radio, different text rules. | router.py:187-193 vs composer.py:31 |
|
||||||
| B11 | **Three incompatible dedup keys** (legacy `(rule,cat,event_id|msg[:50])` in-memory; toggle `(source,event.id)` persisted; rules-path none). |
|
| B11 | **Three incompatible dedup keys** (legacy `(rule,cat,event_id|msg[:50])` in-memory; toggle `(source,event.id)` persisted; rules-path none). |
|
||||||
| B12 | GUI copy bug: severity helper says "Warning" recommended — not a severity level in this system (routine/priority/immediate). Same line still has stale `text-slate-600`. | Notifications.tsx:605 |
|
| B12 | GUI copy bug: severity helper says "Warning" recommended — not a severity level in this system (routine/priority/immediate). Same line still has stale `text-slate-600`. | Notifications.tsx:605 |
|
||||||
|
| B13 | **Guard-ordering trap.** In `_dispatch_toggles`, cooldown is armed (Section 2) and dedup recorded (Section 3) BEFORE the region filter, `min_severity` gate, and `severity_channels` matrix lookup. A below-threshold or wrong-region event consumes the cooldown window and writes a 7-day persisted dedup row, suppressing later events that WOULD deliver — including after the operator fixes config. | dispatcher.py Sections 2-3 vs region/severity/matrix checks |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -121,6 +122,10 @@ notifications:
|
||||||
wired to it honestly.
|
wired to it honestly.
|
||||||
- Migration: for each existing toggle, blank matrix rows below old `min_severity`,
|
- Migration: for each existing toggle, blank matrix rows below old `min_severity`,
|
||||||
map `mesh_broadcast` → auto-created sink from its `broadcast_channel`, etc.
|
map `mesh_broadcast` → auto-created sink from its `broadcast_channel`, etc.
|
||||||
|
- **Session 2 MUST** move the cooldown commit and dedup record to after the delivery
|
||||||
|
decision (region + matrix resolution). Matrix-only semantics inherit the suppression
|
||||||
|
trap otherwise: an event hitting an empty matrix row must not burn its dedup slot
|
||||||
|
or arm a cooldown. (See B13.)
|
||||||
- **Status:** Not yet implemented.
|
- **Status:** Not yet implemented.
|
||||||
|
|
||||||
### GUI changes (when both halves are complete)
|
### GUI changes (when both halves are complete)
|
||||||
|
|
@ -164,3 +169,36 @@ else:
|
||||||
```
|
```
|
||||||
|
|
||||||
*Recorded: 2026-06-10*
|
*Recorded: 2026-06-10*
|
||||||
|
|
||||||
|
### Amendment A2: Layout-aware append-only sinks write
|
||||||
|
|
||||||
|
**Finding:** The original `write_sinks_to_config()` violated Amendment A1 — it
|
||||||
|
unconditionally wrote `config["notifications"]["sinks"]`, creating a bogus
|
||||||
|
`notifications:` wrapper in multi-file configs where the file root IS the
|
||||||
|
notifications block. Additionally, the `yaml.safe_load` → `yaml.dump` round-trip
|
||||||
|
destroyed comments and key ordering.
|
||||||
|
|
||||||
|
**Fix (implemented on this branch):**
|
||||||
|
1. **Shared layout detection.** `detect_config_layout(config)` returns `"monolithic"`,
|
||||||
|
`"multifile"`, or `"empty"`. Both `load_notifications_config()` and
|
||||||
|
`write_sinks_to_config()` use this helper — they cannot diverge.
|
||||||
|
2. **Append-only write.** `render_sinks_yaml(sinks, layout)` produces the exact text
|
||||||
|
to append (indented for monolithic, root-level for multifile). The original file
|
||||||
|
content is preserved byte-for-byte; only the sinks block is appended.
|
||||||
|
3. **Post-write verification.** After writing, `verify_sinks_written()` re-parses
|
||||||
|
the file and asserts: (a) valid YAML, (b) sinks accessible at expected path,
|
||||||
|
(c) original top-level keys intact. On failure, the backup is restored
|
||||||
|
automatically.
|
||||||
|
4. **Dry-run transparency.** `--dry-run` now prints the detected layout, the path
|
||||||
|
where sinks will live (`root-level sinks:` vs `notifications.sinks`), and the
|
||||||
|
exact text that would be appended.
|
||||||
|
|
||||||
|
**Code pattern:**
|
||||||
|
```python
|
||||||
|
layout = detect_config_layout(config)
|
||||||
|
sinks_yaml = render_sinks_yaml(sinks, layout)
|
||||||
|
new_content = original_content + "\n" + sinks_yaml
|
||||||
|
# ... write, then verify_sinks_written() ...
|
||||||
|
```
|
||||||
|
|
||||||
|
*Recorded: 2026-06-11*
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue