nwave-ai/nwave-nw-density-resolution-contract
Shared density-resolution contract for wave skills. Canonical detail on the D12 cascade, density resolver call, ad-hoc override workflow, and DocumentationDensityEvent telemetry emission. Referenced from nw-discover / nw-discuss / nw-design / nw-devops / nw-distill / nw-deliver.
This is a copy. The original lives at nwave-ai/nw-density-resolution-contract.
npx skills add https://github.com/nWave-ai/nWave --skill nw-density-resolution-contract
This skill is the canonical source for the density-aware behaviour every wave skill must implement. Wave skills inherit it by reference and keep a brief inline summary so phrase-grep contract tests stay green; full detail lives here so the same boilerplate is not duplicated six times.
Provenance: feature lean-wave-documentation — D2 (schema-typed sections), D4 (telemetry instrumented day-one), D6 (first-install pedagogical prompt), D10 (one-line expansion descriptions), D12 (rigor cascade), DDD-5 (density resolver shared utility), DDD-6 (telemetry event lives in DES domain).
Each wave emits a single feature-delta.md whose headings are typed [REF] (always emitted) or [WHY]/[HOW] (lazy expansions). Tier-1 is the always-on baseline; Tier-2 is the lazily-rendered expansion catalog. The .feature file (DISTILL) and other machine artifacts remain the SSOT for executable content; the wave-delta sections are pointers + structured summaries.
## Wave: <NAME> / [REF] <Section> headings on every run. Wave-specific list of [REF] sections lives in each wave skill.--expand <id> (DDD-2) or via the wave-end interactive prompt when expansion_prompt = "ask". Each item has a one-line description (per D10) so the menu fits in a single render. Each emitted Tier-2 section is headed ## Wave: <NAME> / [WHY] <Section> or ## Wave: <NAME> / [HOW] <Section>. The catalog itself is wave-specific.Before emitting any Tier-1 section, resolve the active documentation density:
~/.nwave/global-config.json. Treat missing/malformed config as empty dict (fall back to defaults).resolve_density(global_config) from scripts/shared/density_config.py. The function returns a Density value object with fields mode ("lean" | "full"), expansion_prompt ("ask" | "always-skip" | "always-expand" | "smart"), and provenance (the cascade branch that produced this result).density.mode:lean → emit ONLY Tier-1 [REF] sections. Do NOT auto-render Tier-2 items.full → emit Tier-1 [REF] sections PLUS all Tier-2 expansion items rendered under their [WHY] / [HOW] headings. This is auto-expansion (no menu).density.expansion_prompt:"ask" → present the expansion menu (Tier-2 catalog with one-line descriptions per D10) and append user-selected items as ## Wave: <NAME> / [WHY|HOW] <Section> headings."always-skip" → no menu, no extra sections (idempotent re-runs, CI mode)."always-expand" → equivalent to mode = "full" for this run; auto-render every Tier-2 item."smart" → out of scope for v1 (per OQ-3); treat as "ask" until heuristic is empirically tuned.The resolver itself encodes the D12 cascade: explicit documentation.density override > rigor.profile mapping (lean→lean, standard→lean+ask, thorough→full, exhaustive→full+all-expansions, custom→lean+ask) > hard default lean+ask. Wave skills MUST NOT replicate the cascade locally — call resolve_density(global_config) and trust its output.
Section heading prefix convention (per D2): every emitted section starts with ## Wave: <NAME> / [REF] <Section> for Tier-1; ## Wave: <NAME> / [WHY] <Section> or ## Wave: <NAME> / [HOW] <Section> for Tier-2. Validator scripts/validation/validate_feature_delta.py enforces the regex ^## Wave: \w+ / \[(REF|WHY|HOW)\] .+$ on every wave heading.
Even when density.mode = "lean" and density.expansion_prompt = "always-skip", the user may ask DURING the wave session for specific expansions:
<X> is one of the expansion catalog items for this wave)When the user makes such a request:
[WHY] or [HOW] section to feature-delta.md under the current wave's heading.DocumentationDensityEvent with choice="expand" and expansion_id=<the requested item> to JsonlAuditLogWriter.~/.nwave/global-config.json. The override is ONE-SHOT for this wave only.If the user's request matches NO item in the wave's Expansion Catalog, respond with the catalog list (one-line description per item per D10) and ask for clarification — do NOT improvise an expansion outside the catalog.
Every expansion choice — whether the user expanded an item or skipped the menu — emits a structured event to the existing JsonlAuditLogWriter driven adapter.
Event type: DocumentationDensityEvent (dataclass at src/des/domain/telemetry/documentation_density_event.py).
Schema fields (per D4) — substitute the active wave name in the wave field:
{
"feature_id": "<feature-id>",
"wave": "<WAVE-NAME>",
"expansion_id": "<id-from-catalog-or-'*'-for-skip-all>",
"choice": "skip" | "expand",
"timestamp": "<ISO-8601 datetime>"
}
Emission pattern:
DocumentationDensityEvent(feature_id=..., wave="<WAVE>", expansion_id=..., choice=..., timestamp=...).event.to_audit_event() to convert to the open AuditEvent shape (event_type="DOCUMENTATION_DENSITY" and the schema fields nested under data).JsonlAuditLogWriter().log_event(audit_event).The wave-skill harness invokes the helper scripts/shared/telemetry.py:write_density_event(...) which performs all three steps. Wave skills MUST NOT bypass the helper or write JSONL directly — every density telemetry event flows through the shared helper to keep the audit-log schema consistent.
When to emit:
expansion_prompt = "ask" (choice = "expand" for selected items, choice = "skip" with expansion_id = "*" if the user skips the entire menu).choice = "skip" event with expansion_id = "*" when expansion_prompt = "always-skip" (records the skipped menu opportunity).choice = "expand" event per Tier-2 item rendered when mode = "full" or expansion_prompt = "always-expand".This telemetry feeds the propagation success metric: when downstream waves consume a lean upstream feature-delta and produce no --expand, the [REF] baseline plus machine artifacts is sufficient.
Each wave skill keeps a short inline summary that:
## Wave: DISTILL / [REF] <Section>) and lists its own Tier-1 sections + Tier-2 expansion catalog (wave-specific content).## Density resolution heading + the resolver call + the lean/full mode branches + expansion_prompt key + the path ~/.nwave/global-config.json + the resolver path scripts/shared/density_config.py (phrase-grep contract).## Telemetry heading + DocumentationDensityEvent + JsonlAuditLogWriter + to_audit_event + the schema fields (feature_id, expansion_id, choice, timestamp) + the wave-specific "wave": "<WAVE>" literal (phrase-grep contract).D2, D4, D10, D12, DDD-5, DDD-6.The contract phrases are pinned by tests/des/unit/skills/test_wave_skills_density_aware.py; any wave skill missing a phrase fails that test. The shared skill is the source of truth for the BEHAVIOUR; the wave skills are the source of truth for the WAVE-SPECIFIC content (Tier-1 list, Tier-2 catalog, wave heading prefix).
Take nwave-ai/nwave-nw-density-resolution-contract from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.