stream_weaver 0.3.1 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/docs/plans/2026-09-13-audit-report-doc-genre-design.md +438 -0
- data/lib/stream_weaver/org/reader.rb +14 -1
- data/lib/stream_weaver/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0fc050e6a464c6ebf20bcbf71ebfca7ffd93c42adf2791a1dfa40adcffca6856
|
|
4
|
+
data.tar.gz: fa28fa299d91dbd1176182fc5f23240b8d3533772e0c5317354d3c3c68cd1e39
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e38ed59b8ebe99f1d40b802774f518a41f3e630ef4bc7513a1695762618a935e53a6226c4c352c7c9ee6d46c94f9b1b650f6b943c35d39d2c9db99dc7ee0c08f
|
|
7
|
+
data.tar.gz: ada2a295a50ea02c29f271bd9001565cb0e5740af5d87d197ac08a66b774d77144e4e39683feada0dc2c753f822862da295ba419ccad75ac62fb5394872c903f
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.3.2] - 2026-09-11
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- **`Org::Reader` code samples containing real Ruby interpolation crashed rendering** - a `code_block`/`md`/`mermaid` heredoc opened with an unquoted tag (`<<~TXT`), so a code sample legitimately showing Ruby string interpolation (e.g. `"key:#{symbol}"`) got that `#{symbol}` actually evaluated against the rendering `App` instance instead of displayed as text -- `NameError: undefined method 'symbol'`, doc fails to render entirely, both server-side (`canvas-read`, the canvas bridge) and in the Chrome extension (whose JS heredoc rewriter mirrors the same interpolation semantics for the Opal-compiled path). Heredoc tags are now single-quoted (`<<~'TXT'`), so code/prose content is always treated as literal text, matching `emit_table`'s existing `markdown: false` philosophy. Reported via a real Gist RCA doc that wouldn't render.
|
|
12
|
+
|
|
8
13
|
## [0.3.1] - 2026-09-11
|
|
9
14
|
|
|
10
15
|
### Added
|
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
# Audit Report Doc Genre: design
|
|
2
|
+
|
|
3
|
+
Date: 2026-09-13
|
|
4
|
+
Status: design only, no code. Revised 2026-09-13 against the prior-org-decisions brief; Forrest ruled on section 8 the same day (all decided, see there).
|
|
5
|
+
Home repo: stream_weaver (see section 1 for why).
|
|
6
|
+
|
|
7
|
+
## 0. What this is
|
|
8
|
+
|
|
9
|
+
A reusable "audit report" document genre for StreamWeaver: one data contract, three small
|
|
10
|
+
components, one genre-level DSL macro, and one org-mode file schema. Any tool that
|
|
11
|
+
audits something (a guidance file, a skill library, a cabinet API surface) emits the
|
|
12
|
+
contract once and gets the same styled report: score hero, pass/warn/fail finding
|
|
13
|
+
cards, before/after stat panels, numbered owner to-do list.
|
|
14
|
+
|
|
15
|
+
The trigger was a competitor's LLM-generated "vault audit" page. The point here is not
|
|
16
|
+
to copy the page. It is that cultiv-ai already computes the audit data (wwfd-eval,
|
|
17
|
+
skill-ab, the drift detector, idea-ledger) and only the presentation is missing. This
|
|
18
|
+
genre is deterministic code from data to pixels. No LLM in the render path, which is the
|
|
19
|
+
whole cost argument versus routing through Artifact or a chrome mockup loop.
|
|
20
|
+
|
|
21
|
+
## 1. Where it lives and why
|
|
22
|
+
|
|
23
|
+
- **stream_weaver** owns the genre: components, the `audit_report` macro, the org
|
|
24
|
+
reader/writer, the CLI dispatch. Rationale: all four render surfaces (standalone,
|
|
25
|
+
canvas-push, canvas-read, export) are stream_weaver's, and the org round-trip code
|
|
26
|
+
already lives here (`lib/stream_weaver/org/`). cultiv-ai depends on the gem by path
|
|
27
|
+
(Gemfile, locked at 0.3.2), so it picks the genre up with no release step.
|
|
28
|
+
- **cultiv-ai / wwfd** own the producers: each tool grows a thin "emit the contract"
|
|
29
|
+
adapter (a `--audit` flag or a `to_audit_report` method). No styling code lives there.
|
|
30
|
+
|
|
31
|
+
## 2. What already exists (verified, do not rebuild)
|
|
32
|
+
|
|
33
|
+
| Need | Existing primitive | Where | Verdict |
|
|
34
|
+
|---|---|---|---|
|
|
35
|
+
| Document shell | `doc_header`, `doc_section_header`, `sidebar_toc`, `:doc` theme | `lib/stream_weaver/components/doc_header.rb:24-53`, `sidebar_toc.rb`, `theme.rb:199-213` | Reuse as-is |
|
|
36
|
+
| Big number + label | `stat_display(value:, label:, color:, size:)` | `lib/stream_weaver/components.rb:2251-2272` | Reuse inside comparison panels; too small and too bare for the hero |
|
|
37
|
+
| Graded colouring convention | `score_table` thresholds (green >= 70, yellow 40-69, red < 40) | `components.rb:910-921` | Reuse the thresholds, not the component |
|
|
38
|
+
| Two-column before/after | `comparison(before_label:, after_label:) { before {}; after {} }` | `lib/stream_weaver/components/comparison.rb` | Reuse as the layout wrapper |
|
|
39
|
+
| Cards, N-up grid | `card`/`card_header`/`card_body`, `grid columns: [1,2,3]` | `components.rb`, `docs/components_reference.md:182-260` | Reuse |
|
|
40
|
+
| Coloured chip | `badge(text, variant: :success/:warning/:danger)` | `components.rb:2227` | Reuse for the status chip |
|
|
41
|
+
| Severity left-border | `priority_item` CSS pattern | `components.rb:2336` | Copy the CSS idea into `finding_card` |
|
|
42
|
+
| Pass/warn/fail badge | `status_badge(:strong/:maybe/:skip)` | `components.rb:1378` | Do not reuse: labels are domain-hardcoded |
|
|
43
|
+
| Checklist | `md` task lists: kramdown GFM renders `- [ ]`/`- [X]` as static checkboxes | `adapter/alpinejs.rb:2023-2029`, verified by running kramdown | Reuse; needs CSS only (no `.task-list` rules exist in `views.rb`) |
|
|
44
|
+
| Org round-trip | `Org::Reader` / `Org::Writer`, `streamweaver org-export` / `org-render` | `lib/stream_weaver/org/reader.rb`, `cli.rb:2006-2035` | Narrow dialect, see section 6 |
|
|
45
|
+
|
|
46
|
+
Prior-art report shells: `docs/streamweaver_canvas/mailroom-incident-20260813-1123.rb`
|
|
47
|
+
and `pm-discount-feasibility-20260819-1844.rb` (toc + header + numbered sections +
|
|
48
|
+
callouts). None combine the doc shell with the metric components; this genre is the
|
|
49
|
+
first to do so.
|
|
50
|
+
|
|
51
|
+
## 3. Data contract: AuditReport v1
|
|
52
|
+
|
|
53
|
+
Wire format is a plain Hash (YAML or JSON on disk). Every tool already emits JSON or
|
|
54
|
+
YAML, so this is the cheapest thing for a producer to hit. Org is the persisted,
|
|
55
|
+
human-editable form of the same data (section 6); the DSL is the render.
|
|
56
|
+
|
|
57
|
+
```yaml
|
|
58
|
+
audit_report: 1 # schema version, required
|
|
59
|
+
title: "WWFD guidance eval" # required
|
|
60
|
+
subject: "patterns/wwfd-claude-guidance.yaml" # what was audited, optional
|
|
61
|
+
tool: "wwfd-eval" # producer id, optional, shown as a header pill
|
|
62
|
+
generated_at: "2026-09-13T08:40:00-04:00"
|
|
63
|
+
|
|
64
|
+
score: # required: the genre's identity is the hero number
|
|
65
|
+
value: 87 # numeric
|
|
66
|
+
max: 100 # optional; absent means "display value as-is" (a KPI, not a ratio)
|
|
67
|
+
unit: "%" # optional display unit
|
|
68
|
+
grade: "B" # optional; producer-supplied, never derived by the renderer
|
|
69
|
+
label: "Guidance coverage" # required; the small caption under the number
|
|
70
|
+
headline: "7 of 8 patterns pass" # optional; the one-line stat beside the number
|
|
71
|
+
delta: -13 # optional; signed change vs baseline, rendered as a chip
|
|
72
|
+
baseline_label: "baseline 2026-09-01"
|
|
73
|
+
|
|
74
|
+
summary: | # optional markdown, rendered under the hero
|
|
75
|
+
One paragraph of what this audit is and what changed.
|
|
76
|
+
|
|
77
|
+
findings: # optional list; section omitted when empty
|
|
78
|
+
- id: f1 # required, stable, referenced by todos
|
|
79
|
+
status: fail # required: pass | warn | fail | skip
|
|
80
|
+
category: "delegation" # optional short chip (the "framework tag")
|
|
81
|
+
title: "Delegation ladder is not a trigger" # required
|
|
82
|
+
body: | # optional markdown
|
|
83
|
+
The guidance names the failure mode but never fires on it.
|
|
84
|
+
owner: forrest # optional
|
|
85
|
+
fix: "Add lean-coordinator as a pattern trigger" # optional recommended action
|
|
86
|
+
fixed: false # optional; true means "fix applied", rendered as a struck/green state
|
|
87
|
+
|
|
88
|
+
before_after: # optional; section omitted when absent
|
|
89
|
+
before_label: "Baseline 2026-09-01"
|
|
90
|
+
after_label: "This run"
|
|
91
|
+
metrics:
|
|
92
|
+
- label: "Score"
|
|
93
|
+
before: 100
|
|
94
|
+
after: 87
|
|
95
|
+
unit: "%"
|
|
96
|
+
good: up # up | down | none: which direction is an improvement
|
|
97
|
+
|
|
98
|
+
fixes_applied: # optional list of {title, body}; rendered as success callouts
|
|
99
|
+
- title: "Renamed trigger X"
|
|
100
|
+
body: "…"
|
|
101
|
+
|
|
102
|
+
todos: # optional; section omitted when empty
|
|
103
|
+
- title: "Add delegation-ladder trigger"
|
|
104
|
+
owner: forrest
|
|
105
|
+
due: 2026-09-20
|
|
106
|
+
done: false
|
|
107
|
+
ref: f1 # optional finding id; renders as a link to the card
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Rules the renderer enforces:
|
|
111
|
+
|
|
112
|
+
- `skip` is a real fourth status ("could not evaluate"), not a warn. The drift detector's
|
|
113
|
+
`:error` state and skill-ab's `not_yet_tested` both need it.
|
|
114
|
+
- Findings render fail, then warn, then pass, then skip. Counts per status go in the
|
|
115
|
+
section header as chips, so the "what the audit found" summary is free.
|
|
116
|
+
- The hero colour follows `score_table`'s thresholds on `value / max` when `max` is
|
|
117
|
+
present, and is neutral when it is absent. Grade is display-only.
|
|
118
|
+
- Everything except `audit_report`, `title`, and `score` is optional. A report with
|
|
119
|
+
only a hero and a before/after block (delegation-roi) is valid.
|
|
120
|
+
|
|
121
|
+
### 3.1 How each cultiv-ai tool maps onto it
|
|
122
|
+
|
|
123
|
+
| Tool | score | findings.status | before/after | todos | Fit |
|
|
124
|
+
|---|---|---|---|---|---|
|
|
125
|
+
| wwfd-eval | percent, real `delta` vs `evals/baseline.json` | 1/0 per pattern -> pass/fail | baseline vs current score, natively | failed patterns | Strong |
|
|
126
|
+
| skill-ab report | share of skills with `earns_its_place` | earns_its_place->pass, inconclusive/not_yet_tested->warn/skip, deletion_candidate->fail | bare vs skill arm counts | deletion candidates, low-agreement skills | Good, lossy remap |
|
|
127
|
+
| Drift detector | `(total - failures) / total` | clean->pass, violations->fail, error->skip | none | `ScanProposal.proposed_action` | Good |
|
|
128
|
+
| idea-ledger report | derived from counts (shipped share) | shipped->pass, advancing->warn, declined->fail, filed->skip | none | its "Follow-ups" section | Usable, semantics stretched |
|
|
129
|
+
| delegation-roi | `minutes_saved`, no max | none (empty list) | window vs prior window, natively | none | Hero + before/after only |
|
|
130
|
+
| meeting-signals | none | none | none | owner + item rows | Poor; to-do only, do not force |
|
|
131
|
+
|
|
132
|
+
`ScanProposal` (`lib/cultiv_cabinet/secretary/scan_proposal.rb`) is already the shared
|
|
133
|
+
per-finding record across dozens of scans. A one-method mapping (`trigger_condition` ->
|
|
134
|
+
title, `proposed_action` -> fix, `urgency` P0/P1/P2 -> fail/warn/pass, `route_to` ->
|
|
135
|
+
owner, `proposal_type` -> category) turns every existing scanner into a producer without
|
|
136
|
+
touching the scanners.
|
|
137
|
+
|
|
138
|
+
## 4. Component set
|
|
139
|
+
|
|
140
|
+
Four additions to stream_weaver: three components and one macro. All static, canvas-safe by construction (no
|
|
141
|
+
`sendEvent`, no state), so they work in live canvas, canvas-read, and export. Each
|
|
142
|
+
needs the Alpine adapter render, the static adapter render, CSS in the `views.rb`
|
|
143
|
+
stylesheet heredoc (`sw-` BEM), and a `spec/components_spec.rb` block, following the
|
|
144
|
+
`stat_display` pattern (`components.rb:2251`, `display_dsl.rb:161`,
|
|
145
|
+
`adapter/alpinejs.rb:7129-7136`, `views.rb:2862+`).
|
|
146
|
+
|
|
147
|
+
1. **`score_hero(value:, label:, max: nil, unit: nil, grade: nil, headline: nil, delta: nil, baseline_label: nil)`**
|
|
148
|
+
New. A hero band: the number at display-font scale with the grade beside it, the
|
|
149
|
+
label under, the headline stat and delta chip to the right. Reuses the `.sw-stat`
|
|
150
|
+
colour vocabulary. Why not `stat_display size: :xl`: the hero needs three extra
|
|
151
|
+
slots (grade, headline, delta), not a bigger font.
|
|
152
|
+
2. **`finding_card(status:, title:, category: nil, owner: nil, fixed: false) { body }`**
|
|
153
|
+
New, thin. `card` with a status-coloured left border (the `priority_item` idea), a
|
|
154
|
+
`badge` chip for the status, a muted chip for the category, and an optional owner
|
|
155
|
+
line in the footer. `fixed: true` swaps the chip to "fixed" and dims the card.
|
|
156
|
+
3. **`stat_comparison(before_label:, after_label:, metrics: [...])`**
|
|
157
|
+
New, thin. `comparison` layout with one `stat_display` per metric in each panel, plus
|
|
158
|
+
a delta chip coloured by `good:`. Why a component and not a macro: the org reader and
|
|
159
|
+
writer need one construct to map a table onto, and export parity needs one render
|
|
160
|
+
method.
|
|
161
|
+
4. **`audit_report(data)`** the genre macro, the single chokepoint.
|
|
162
|
+
Takes the contract Hash and emits: `sidebar_toc` (only for sections present),
|
|
163
|
+
`doc_header` (eyebrow = tool, title, pills = date, subject, grade), `score_hero`,
|
|
164
|
+
summary `md`, section 1 "What the audit found" as `grid columns: [1,2,3]` of
|
|
165
|
+
`finding_card`, section 2 `stat_comparison`, section 3 fixes as `callout(:success)`
|
|
166
|
+
rows, section 4 the to-do list as one `md` block of GFM checkbox lines in the fixed
|
|
167
|
+
convention `- [ ] title · owner · due · ref:f1`, preceded by an `[n/N]` cookie the
|
|
168
|
+
macro computes from `done` at render time (Forrest's ruling, decision 5). No
|
|
169
|
+
checklist component: kramdown already renders task lists as static checkboxes, so
|
|
170
|
+
the only work is `.task-list` CSS in `views.rb`. Validates the contract and raises with a path on the
|
|
171
|
+
first bad field, so a producer bug is a loud error and not a half-rendered page.
|
|
172
|
+
Lives in a new `lib/stream_weaver/genres/audit_report.rb` and registers one DSL
|
|
173
|
+
method; the doc-builder skill gains a short "audit report" reference section.
|
|
174
|
+
|
|
175
|
+
Standalone use is the doc-builder body pattern unchanged:
|
|
176
|
+
|
|
177
|
+
```ruby
|
|
178
|
+
# streamweaver-doc: v1
|
|
179
|
+
audit_report YAML.safe_load_file("wwfd-eval-2026-09-13.yaml", symbolize_names: true)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
and `streamweaver canvas-push audit < body.rb` pushes it.
|
|
183
|
+
|
|
184
|
+
## 5. Render pipeline
|
|
185
|
+
|
|
186
|
+
```
|
|
187
|
+
producer (wwfd-eval, skill-ab, ...) --emits--> contract YAML/JSON (wire format, not persisted)
|
|
188
|
+
|
|
|
189
|
+
audit_report(hash) DSL body
|
|
190
|
+
|
|
|
191
|
+
streamweaver org-export (existing Org::Writer, extended)
|
|
192
|
+
v
|
|
193
|
+
report.org <-- greppable, diffable, versioned source of truth
|
|
194
|
+
|
|
|
195
|
+
Org::Reader (existing, extended) <-- canvas-read, org-render, extension preview
|
|
196
|
+
v
|
|
197
|
+
DSL --> standalone | canvas-push | canvas-read | export
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Nothing new at the CLI. The `.org` file is a plain instance of the shipped StreamWeaver
|
|
201
|
+
org dialect (`docs/superpowers/specs/2026-08-13-org-doc-format-design.md`), so every
|
|
202
|
+
surface that already understands that dialect delivers the genre for free: canvas-read
|
|
203
|
+
native `.org` (S1 in `docs/plans/org-doc-preview-surfaces.md`, shipped), the browser
|
|
204
|
+
extension's local-file drag-drop and Gist preview (S2, S3, shipped), and `org-render |
|
|
205
|
+
canvas-push`. Two surfaces do not take `.org` yet and are out of scope here:
|
|
206
|
+
`canvas-push` pipes stdin verbatim (hence the `org-render` step), and `streamweaver
|
|
207
|
+
export file.org` fails today (open mark disc-175); static HTML of an audit comes from
|
|
208
|
+
canvas-read's export or from `org-render file.org > body.rb` then `export body.rb`. The first line stays the literal `#+STREAMWEAVER_DSL: 1` so
|
|
209
|
+
every detection surface (content.js, sandbox.js, canvas-read, `doc_store.rb:167`) keeps
|
|
210
|
+
working.
|
|
211
|
+
|
|
212
|
+
There is no hand-rolled org emitter and no second parser. Producers never write org
|
|
213
|
+
directly; they hand a Hash to `audit_report`, and the existing writer serialises the
|
|
214
|
+
expanded component tree. orgkit is not a dependency of the genre. It becomes relevant
|
|
215
|
+
only if a tool later needs to mutate an existing report file in place (for example
|
|
216
|
+
ticking a to-do box), which is orgkit's byte-span mutation contract and
|
|
217
|
+
out of scope here.
|
|
218
|
+
|
|
219
|
+
No LLM is called anywhere in this pipeline. The token cost of showing an audit is the
|
|
220
|
+
cost of one `canvas-push` of a one-line body, or zero if the reader opens the `.org`
|
|
221
|
+
in canvas-read.
|
|
222
|
+
|
|
223
|
+
## 6. Org schema for the source file
|
|
224
|
+
|
|
225
|
+
The peer session's prior-decisions brief (2026-09-13) rules that the audit `.org` must
|
|
226
|
+
be an instance of the shipped dialect, not a parallel one: callouts and cards ride
|
|
227
|
+
inside `#+begin_quote` because org-ruby drops unknown block types entirely, the
|
|
228
|
+
round-trip bar is rendered-equivalent not byte-identical, and no hand-rolled org
|
|
229
|
+
emitters. This section is designed to that ruling. An earlier draft of this section
|
|
230
|
+
used tags, free property drawers and TODO headlines; it was dropped because the
|
|
231
|
+
dialect's reader has none of those (`reader.rb:29` numbered headlines only,
|
|
232
|
+
`reader.rb:215-223` two property keys and a mandatory `CUSTOM_ID`).
|
|
233
|
+
|
|
234
|
+
### 6.1 Principle: the components self-identify, the genre needs no reader
|
|
235
|
+
|
|
236
|
+
The four new components each get one org construct that (a) is a real org element
|
|
237
|
+
every generic renderer already shows, (b) is discriminated by the dialect's existing
|
|
238
|
+
mechanisms (quote-block marker line, `#+ATTR_STREAMWEAVER:` on a table), and (c)
|
|
239
|
+
degrades to the nearest plain construct in a viewer that does not know StreamWeaver.
|
|
240
|
+
Because the components self-identify, `#+STREAMWEAVER_GENRE: audit_report` is
|
|
241
|
+
advisory metadata only (tolerated by `PREAMBLE_RE`, `reader.rb:47`); the file is an
|
|
242
|
+
ordinary dialect doc that happens to use these constructs. No genre dispatch, no
|
|
243
|
+
reserved section names.
|
|
244
|
+
|
|
245
|
+
| Component | Org construct | Discriminator (Phase 3 addition to the dialect) | Degrades to |
|
|
246
|
+
|---|---|---|---|
|
|
247
|
+
| `score_hero` | quote block | marker line starts with `*🎯 ` (new reserved emoji, rule 3 table) | a blockquote showing the score |
|
|
248
|
+
| `finding_card` | quote block, card syntax | card whose `[badge]` is exactly `pass`, `warn`, `fail` or `skip` (rule 4 refinement); `/(meta)/` is the category | a plain card |
|
|
249
|
+
| `stat_comparison` | org table | `#+ATTR_STREAMWEAVER: :stat_comparison t :before "…" :after "…"` on the line before | a plain table |
|
|
250
|
+
| to-do list | plain org checkbox list inside prose | none needed; it is ordinary `md` text to the reader (`reader.rb:327-330`) and round-trips byte-identical | a native org checkbox list |
|
|
251
|
+
| fixes applied | existing ✅ callout | none needed | already in dialect |
|
|
252
|
+
| sections | existing numbered headlines with `:CUSTOM_ID:` | none needed | already in dialect |
|
|
253
|
+
|
|
254
|
+
Finding scalar fields that have no slot in the card syntax (`id`, `owner`, `fix`,
|
|
255
|
+
`fixed`) ride as git-style trailer lines at the end of the card body: `Id: f1`,
|
|
256
|
+
`Owner: forrest`, `Fix: …`, `Fixed: yes`. The reader strips recognised trailers into
|
|
257
|
+
the component; anything else stays body text.
|
|
258
|
+
|
|
259
|
+
### 6.2 The file
|
|
260
|
+
|
|
261
|
+
```org
|
|
262
|
+
#+STREAMWEAVER_DSL: 1
|
|
263
|
+
#+TITLE: WWFD guidance eval
|
|
264
|
+
#+STREAMWEAVER_GENRE: audit_report
|
|
265
|
+
#+DATE: 2026-09-13
|
|
266
|
+
|
|
267
|
+
#+begin_quote
|
|
268
|
+
wwfd-eval
|
|
269
|
+
WWFD guidance eval
|
|
270
|
+
2026-09-13 · patterns/wwfd-claude-guidance.yaml · [B](good)
|
|
271
|
+
#+end_quote
|
|
272
|
+
|
|
273
|
+
#+begin_quote
|
|
274
|
+
*🎯 87/100% B — Guidance coverage*
|
|
275
|
+
7 of 8 patterns pass
|
|
276
|
+
Δ -13 vs baseline 2026-09-01
|
|
277
|
+
#+end_quote
|
|
278
|
+
|
|
279
|
+
One paragraph of summary. Plain org prose, rendered as markdown.
|
|
280
|
+
|
|
281
|
+
* 1 What the audit found
|
|
282
|
+
:PROPERTIES:
|
|
283
|
+
:CUSTOM_ID: findings
|
|
284
|
+
:END:
|
|
285
|
+
|
|
286
|
+
#+begin_quote
|
|
287
|
+
*[fail] Delegation ladder is not a trigger* /(delegation)/
|
|
288
|
+
The guidance names the failure mode but never fires on it.
|
|
289
|
+
|
|
290
|
+
Id: f1
|
|
291
|
+
Owner: forrest
|
|
292
|
+
Fix: Add lean-coordinator as a pattern trigger
|
|
293
|
+
Fixed: no
|
|
294
|
+
#+end_quote
|
|
295
|
+
|
|
296
|
+
#+begin_quote
|
|
297
|
+
*[pass] Complexity skepticism* /(complexity_skepticism)/
|
|
298
|
+
The guidance explicitly names the failure mode and gives the concrete instruction.
|
|
299
|
+
|
|
300
|
+
Id: f2
|
|
301
|
+
#+end_quote
|
|
302
|
+
|
|
303
|
+
* 2 Before and after
|
|
304
|
+
:PROPERTIES:
|
|
305
|
+
:CUSTOM_ID: before-after
|
|
306
|
+
:END:
|
|
307
|
+
|
|
308
|
+
#+ATTR_STREAMWEAVER: :stat_comparison t :before "Baseline 2026-09-01" :after "This run"
|
|
309
|
+
| Metric | Before | After | Unit | Good |
|
|
310
|
+
|---|---|---|---|---|
|
|
311
|
+
| Score | 100 | 87 | % | up |
|
|
312
|
+
| Patterns passing | 8 | 7 | | up |
|
|
313
|
+
|
|
314
|
+
* 3 Fixes applied
|
|
315
|
+
:PROPERTIES:
|
|
316
|
+
:CUSTOM_ID: fixes
|
|
317
|
+
:END:
|
|
318
|
+
|
|
319
|
+
#+begin_quote
|
|
320
|
+
*✅ Renamed trigger X*
|
|
321
|
+
Body of what was changed.
|
|
322
|
+
#+end_quote
|
|
323
|
+
|
|
324
|
+
* 4 Owner to-do
|
|
325
|
+
:PROPERTIES:
|
|
326
|
+
:CUSTOM_ID: todo
|
|
327
|
+
:END:
|
|
328
|
+
|
|
329
|
+
Owner to-do [1/2]
|
|
330
|
+
|
|
331
|
+
- [ ] Add delegation-ladder trigger · forrest · 2026-09-20 · ref:f1
|
|
332
|
+
- [X] Re-run wwfd-eval after the rename · forrest
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
Greppability in practice: `grep -l '^\*\[fail\]' reports/*.org` lists every audit
|
|
336
|
+
with an open failure; `grep -h '^\*🎯' reports/*.org` is the score history; `git diff`
|
|
337
|
+
on a re-run shows exactly which cards flipped badge and which boxes got ticked;
|
|
338
|
+
`grep -h '^- \[ \]' reports/*.org` is every open to-do across all audits. Editing by
|
|
339
|
+
hand is changing `[fail]` to `[pass]` or `[ ]` to `[X]`. Owner, due and ref are
|
|
340
|
+
text-by-convention, so promotion to UTF reads them with one regex; the report keeps
|
|
341
|
+
the checked snapshot with the ref, which is the org-native shape for that.
|
|
342
|
+
|
|
343
|
+
### 6.3 What the Phase 3 dialect extension touches
|
|
344
|
+
|
|
345
|
+
Small, and all inside the existing reader and writer:
|
|
346
|
+
|
|
347
|
+
- `Org::Reader`: add 🎯 as a score marker (a separate table from `VARIANT_EMOJI` so
|
|
348
|
+
callouts are untouched); in `emit_card` (`reader.rb:427`) route badge ∈
|
|
349
|
+
{pass, warn, fail, skip} to `finding_card` and parse trailers; in `emit_table`
|
|
350
|
+
(`reader.rb:332`) honour `:stat_comparison` in `pending_attr` alongside `:markdown`.
|
|
351
|
+
- `Org::Writer`: three new `when` branches in `render_component` (`writer.rb:137`) so
|
|
352
|
+
the components stop falling into the `:streamweaver-raw` escape hatch, which is what
|
|
353
|
+
would happen today and is neither greppable nor editable.
|
|
354
|
+
- The spec gets a dated Phase 3 section listing the two quote-block discriminators and the one
|
|
355
|
+
table attribute, with the rule-3 emoji table extended and the rule-4 badge
|
|
356
|
+
refinement stated as an accepted edge case (a plain card badged literally "pass" is
|
|
357
|
+
a finding card; do not badge ordinary cards with those four words).
|
|
358
|
+
- Round-trip spec: `spec/org/round_trip_spec.rb` gains the file above and asserts
|
|
359
|
+
rendered-equivalence.
|
|
360
|
+
- Body emission rule for the macro: `finding_card` and callout bodies must be emitted
|
|
361
|
+
with `md`, never `text`, and must not nest other components. `Org::Writer` has no
|
|
362
|
+
case arm for `text` or nested components inside a callout and drops them silently on
|
|
363
|
+
export (open mark disc-170). The contract already makes `body` markdown, so this is a
|
|
364
|
+
constraint on the macro, not on producers.
|
|
365
|
+
|
|
366
|
+
Accepted trade-off (decided): a checkbox list is invisible to org-agenda. `TODO`/`DONE`
|
|
367
|
+
headlines with `DEADLINE:` would need the dialect to learn TODO keywords and unnumbered
|
|
368
|
+
headlines, a bigger change than the genre justifies; revisit only if agenda visibility
|
|
369
|
+
turns out to matter.
|
|
370
|
+
|
|
371
|
+
## 7. First consumer and build sequence
|
|
372
|
+
|
|
373
|
+
### 7.1 First consumer: wwfd-eval
|
|
374
|
+
|
|
375
|
+
Chosen over the two flagged candidates:
|
|
376
|
+
|
|
377
|
+
- **skill-ab report** has zero recorded runs in this environment. There is no real data
|
|
378
|
+
to prototype against, and a report designed against a synthetic fixture is the kind of
|
|
379
|
+
demo-first work the AI Theater test exists to catch. It is the right second consumer:
|
|
380
|
+
its verdict remap and deletion candidates exercise the warn/skip statuses and the
|
|
381
|
+
to-do section that wwfd-eval does not.
|
|
382
|
+
- **coherence-check** is really two things. The CLI is unstructured RSpec prose and its
|
|
383
|
+
own header documents why that was abandoned. The structured half, the drift detector,
|
|
384
|
+
is quiet-on-success, has no before/after, and does not itemise findings past four fixed
|
|
385
|
+
category labels.
|
|
386
|
+
- **wwfd-eval** has real data on disk today (`evals/baseline.json`, 8 per-pattern results
|
|
387
|
+
with reasoning), the only genuine persisted baseline-versus-current score delta in the
|
|
388
|
+
whole set, one finding per pattern with a category and a body, and a to-do list that
|
|
389
|
+
falls out of the failures. It exercises the hero, the finding grid, and the before/after
|
|
390
|
+
block with real values on day one. It is also run by protocol before every WWFD change
|
|
391
|
+
(the global CLAUDE.md change protocol), so the report changes a real decision, commit or
|
|
392
|
+
not, on a recurring basis rather than being looked at once.
|
|
393
|
+
|
|
394
|
+
Its one gap, binary pass/fail with no warn, is fine: warn is optional in the contract and
|
|
395
|
+
skill-ab covers it next.
|
|
396
|
+
|
|
397
|
+
### 7.2 Sequence (pareto rigor: lanes, rigor per story)
|
|
398
|
+
|
|
399
|
+
| Step | Lane | Rigor | What | Done when |
|
|
400
|
+
|---|---|---|---|---|
|
|
401
|
+
| 1 | components | strict | `score_hero`, `finding_card`, `stat_comparison`: class, DSL, Alpine + static adapters, CSS, specs; `.task-list` CSS for md checkbox lists | `bundle exec rspec` green; `examples/canvas-safe-showcase.rb` gains all three plus a checkbox list; export of the showcase renders them |
|
|
402
|
+
| 2 | components | strict | `audit_report(hash)` macro with contract validation, `examples/audit_report/` body + wrapper, doc-builder skill section | A hand-written YAML matching section 3 renders standalone and via canvas-push identically |
|
|
403
|
+
| 3 | consumer | loose | A 30-line script in wwfd turning `evals/baseline.json` plus a fresh run into contract YAML; push to canvas; Forrest reviews the real thing | Forrest has seen a real wwfd audit on canvas. This is the SDRD checkpoint: the visual reveals what v2 should be before the org work is built |
|
|
404
|
+
| 4 | org | strict | Phase 3 dialect extension: writer branches, reader discriminators and the table attribute, spec amendment, round-trip spec | `org-export` of the step-3 body produces the section 6.2 shape with no `:streamweaver-raw` blocks; `org-render` of it back renders equivalent; canvas-read opens the `.org` directly |
|
|
405
|
+
| 5 | consumer | loose | `bin/wwfd-eval --audit PATH.yaml` in wwfd; `bin/skill-ab report --audit` in cultiv-ai once it has runs; a `ScanProposal` -> finding mapper | Two producers, zero styling code in either repo |
|
|
406
|
+
|
|
407
|
+
Steps 1 and 2 are one warmed builder lane (same files). Step 3 comes before step 4 on
|
|
408
|
+
purpose: seeing the rendered report with real data is cheaper than guessing. Steps 4
|
|
409
|
+
and 5 can run in parallel once 3 is reviewed. Verification item for step 4: confirm
|
|
410
|
+
`Org::Writer.from_dsl` sees the components `audit_report` expands to, not the macro
|
|
411
|
+
call itself (it records the component tree via the recording context, so it should).
|
|
412
|
+
|
|
413
|
+
## 8. Decisions (ruled by Forrest, 2026-09-13)
|
|
414
|
+
|
|
415
|
+
1. **Home repo: stream_weaver** owns the genre; cultiv-ai and wwfd own producer
|
|
416
|
+
adapters only. (Alternative rejected: cultiv-ai `lib/stream_weaver_ext/`.)
|
|
417
|
+
2. **Phase 3 dialect extension: yes.** Two quote-block discriminators (🎯 score marker,
|
|
418
|
+
pass/warn/fail/skip card badge) and one table attribute (`:stat_comparison`) amend
|
|
419
|
+
the shipped org-doc-format spec, so the three components never fall into the raw
|
|
420
|
+
escape hatch on export.
|
|
421
|
+
3. **Static checklist: moot** under decision 5; a checkbox list is inherently static.
|
|
422
|
+
4. **First consumer: wwfd-eval**, skill-ab second once it has recorded runs.
|
|
423
|
+
5. **To-dos: option C, a plain org checkbox list** in the convention
|
|
424
|
+
`- [ ] title · owner · due · ref:f1`, with the macro writing the `[n/N]` cookie.
|
|
425
|
+
The `checklist` component and the `:checklist t` table attribute are removed from
|
|
426
|
+
the plan (three new components, not four). Rationale: live items get promoted to
|
|
427
|
+
UTF and the report keeps a checked snapshot with the ref; checkboxes are the
|
|
428
|
+
org-native shape for that, and kramdown already renders them (section 2).
|
|
429
|
+
(Alternatives rejected: a `:checklist` table; `TODO`/`DONE` headlines.)
|
|
430
|
+
|
|
431
|
+
## 9. Sources
|
|
432
|
+
|
|
433
|
+
Survey reports from this session (scratchpad, not in repo): stream_weaver primitives and
|
|
434
|
+
org reader scope; cultiv-ai and wwfd tool output shapes; orgkit and cultiv-ai org
|
|
435
|
+
conventions. Key repo references: `docs/superpowers/specs/2026-08-13-org-doc-format-design.md`
|
|
436
|
+
(existing org dialect), `lib/stream_weaver/skills/streamweaver-doc-builder/SKILL.md`,
|
|
437
|
+
`lib/stream_weaver/skills/streamweaver-canvas-safe/SKILL.md`, Tyrion marks disc-170,
|
|
438
|
+
disc-175, disc-182 (org gaps).
|
|
@@ -532,13 +532,26 @@ module StreamWeaver
|
|
|
532
532
|
# closing tag -- get this backwards and the emitted Ruby won't parse.
|
|
533
533
|
# Also guards against a body line that happens to equal the tag itself
|
|
534
534
|
# (which would terminate the heredoc early) by picking a fresh tag.
|
|
535
|
+
#
|
|
536
|
+
# The opening tag is single-quoted (`<<~'TAG'`), NOT bare -- md/mermaid/
|
|
537
|
+
# code_block content is verbatim prose or source code being displayed,
|
|
538
|
+
# never something that should be re-interpreted as Ruby. A bare `<<~TAG`
|
|
539
|
+
# heredoc still performs string interpolation and backslash escapes, so
|
|
540
|
+
# a code sample showing real Ruby string interpolation (e.g.
|
|
541
|
+
# `"key:#{symbol}"`) got that `#{symbol}` actually evaluated against the
|
|
542
|
+
# rendering App instance at instance_eval time, raising a NameError
|
|
543
|
+
# instead of displaying the snippet (reported: a real-world RCA gist
|
|
544
|
+
# with `"corporate-actions-catch-up:#{symbol}"` in a code_block
|
|
545
|
+
# wouldn't render -- "undefined method `symbol'"). Quoting the tag
|
|
546
|
+
# disables both, matching the "preserve literal text" behavior emit_table
|
|
547
|
+
# already relies on for markdown: false tables.
|
|
535
548
|
def heredoc(prefix, text, base_tag, suffix: "")
|
|
536
549
|
tag = unique_heredoc_tag(base_tag, text)
|
|
537
550
|
content = text.split("\n", -1)
|
|
538
551
|
content.pop if content.last == ""
|
|
539
552
|
content = [""] if content.empty?
|
|
540
553
|
|
|
541
|
-
"#{prefix}
|
|
554
|
+
"#{prefix}<<~'#{tag}'#{suffix}\n#{content.map { |line| line.empty? ? line : " #{line}" }.join("\n")}\n#{tag}"
|
|
542
555
|
end
|
|
543
556
|
|
|
544
557
|
def unique_heredoc_tag(base_tag, text)
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: stream_weaver
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Forrest Chang
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-09-
|
|
11
|
+
date: 2026-09-14 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: sinatra
|
|
@@ -240,6 +240,7 @@ files:
|
|
|
240
240
|
- docs/plans/2026-01-10-canvas-ipc-design.md
|
|
241
241
|
- docs/plans/2026-01-19-cabinet-control-components.md
|
|
242
242
|
- docs/plans/2026-01-26-gem-release-and-panel.md
|
|
243
|
+
- docs/plans/2026-09-13-audit-report-doc-genre-design.md
|
|
243
244
|
- docs/plans/canvas-claude-project-design.md
|
|
244
245
|
- docs/plans/canvas-doc-location-and-discovery.md
|
|
245
246
|
- docs/plans/org-doc-preview-surfaces.md
|