Skip to content

chore(deps): bump actions/upload-artifact from 4.6.2 to 7.0.0#2

Closed
dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/github_actions/actions/upload-artifact-7.0.0
Closed

chore(deps): bump actions/upload-artifact from 4.6.2 to 7.0.0#2
dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/github_actions/actions/upload-artifact-7.0.0

Conversation

@dependabot
Copy link
Copy Markdown
Contributor

@dependabot dependabot Bot commented on behalf of github Mar 14, 2026

Bumps actions/upload-artifact from 4.6.2 to 7.0.0.

Release notes

Sourced from actions/upload-artifact's releases.

v7.0.0

v7 What's new

Direct Uploads

Adds support for uploading single files directly (unzipped). Callers can set the new archive parameter to false to skip zipping the file during upload. Right now, we only support single files. The action will fail if the glob passed resolves to multiple files. The name parameter is also ignored with this setting. Instead, the name of the artifact will be the name of the uploaded file.

ESM

To support new versions of the @actions/* packages, we've upgraded the package to ESM.

What's Changed

New Contributors

Full Changelog: actions/upload-artifact@v6...v7.0.0

v6.0.0

v6 - What's new

[!IMPORTANT] actions/upload-artifact@v6 now runs on Node.js 24 (runs.using: node24) and requires a minimum Actions Runner version of 2.327.1. If you are using self-hosted runners, ensure they are updated before upgrading.

Node.js 24

This release updates the runtime to Node.js 24. v5 had preliminary support for Node.js 24, however this action was by default still running on Node.js 20. Now this action by default will run on Node.js 24.

What's Changed

Full Changelog: actions/upload-artifact@v5.0.0...v6.0.0

v5.0.0

What's Changed

BREAKING CHANGE: this update supports Node v24.x. This is not a breaking change per-se but we're treating it as such.

... (truncated)

Commits
  • bbbca2d Support direct file uploads (#764)
  • 589182c Upgrade the module to ESM and bump dependencies (#762)
  • 47309c9 Merge pull request #754 from actions/Link-/add-proxy-integration-tests
  • 02a8460 Add proxy integration test
  • b7c566a Merge pull request #745 from actions/upload-artifact-v6-release
  • e516bc8 docs: correct description of Node.js 24 support in README
  • ddc45ed docs: update README to correct action name for Node.js 24 support
  • 615b319 chore: release v6.0.0 for Node.js 24 support
  • 017748b Merge pull request #744 from actions/fix-storage-blob
  • 38d4c79 chore: rebuild dist
  • Additional commits viewable in compare view

Dependabot compatibility score

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


Dependabot commands and options

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot show <dependency name> ignore conditions will show all of the ignore conditions of the specified dependency
  • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)

@dependabot dependabot Bot added dependencies Pull requests that update a dependency file github_actions Pull requests that update GitHub Actions code labels Mar 14, 2026
@vercel
Copy link
Copy Markdown

vercel Bot commented Mar 14, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
mean-beoynd-lite-pwa Ready Ready Preview, Comment Mar 14, 2026 9:36am
variscout_website Ready Ready Preview, Comment Mar 14, 2026 9:36am

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.6.2 to 7.0.0.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](actions/upload-artifact@ea165f8...bbbca2d)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: 7.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
@jukka-matti
Copy link
Copy Markdown
Owner

Applied this update directly on main in a consolidated dependency bump commit (all 13 Dependabot updates at once). Closing this PR.

@dependabot @github
Copy link
Copy Markdown
Contributor Author

dependabot Bot commented on behalf of github Mar 20, 2026

OK, I won't notify you again about this release, but will get in touch when a new version is available. If you'd rather skip all updates until the next major or minor version, let me know by commenting @dependabot ignore this major version or @dependabot ignore this minor version. You can also ignore all major, minor, or patch releases for a dependency by adding an ignore condition with the desired update_types to your config file.

If you change your mind, just re-open this PR and I'll resolve any conflicts on it.

@dependabot dependabot Bot deleted the dependabot/github_actions/actions/upload-artifact-7.0.0 branch March 20, 2026 12:56
jukka-matti added a commit that referenced this pull request Apr 26, 2026
Defers #2 (full i18n sweep) — that spans the whole apps/azure app, not
just process hub; track separately.

- processHub.ts: orphan/synthesized hubs now get a friendly fallback name
  ('Unknown hub') instead of rendering the raw hubId. Applies to both
  investigation-derived and evidence-snapshot-derived synthesized hubs.
- ProcessHubEvidencePanel.tsx: false-green severity is now rate-based —
  0 false greens → green, ≤1% rate → amber, >1% → red. Replaces the
  hardcoded red-for-any-count default. Threshold (FALSE_GREEN_AMBER_RATE)
  exposed as a constant; Phase 6 spec can refine.
- @variscout/core/i18n: new formatPlural() helper using Intl.PluralRules.
  Applied to ProcessHubCard + ProcessHubReviewPanel (replacing hand-rolled
  "investigation"+"s", formatChangeSignals, formatOverdueActions). Helper
  is locale-aware (Polish 'few' tested) and required-other-fallback safe.
- ProcessHubReviewPanel.tsx: split from 549 LOC into 4 focused files:
    ProcessHubReviewPanel.tsx       106 LOC  (orchestrator)
    ProcessHubCadenceQuestions.tsx   37 LOC  (3 cadence question bands)
    ProcessHubCadenceQueues.tsx     363 LOC  (daily + weekly columns)
    ProcessHubFormat.ts              93 LOC  (shared format helpers)
  Tests stay green (16/16) — pure structural refactor.

Co-Authored-By: ruflo <ruv@ruv.net>
jukka-matti added a commit that referenced this pull request Apr 27, 2026
Lift the Azure-only ProcessHubCurrentStatePanel into @variscout/ui
so Phase 2 snapshot-mode work in LayeredProcessView can compose with
it from a shared home. Component is fully props-based — takes
CurrentProcessState in, renders JSX out — no Azure-specific deps
(Blob Storage, EasyAuth, app stores).

The two formatter dependencies (formatMetric, formatChangeSignals)
that previously lived in Azure's ProcessHubFormat helper are inlined
here using the canonical formatStatistic + formatPlural from
@variscout/core/i18n.

Adds 8 unit tests covering: heading + severity badge, lens count
cards, empty state, +N indicator at >6 items, Cpk-vs-target detail,
change-signal pluralization, detail fallback, response-path label.

PWA does not get this panel — Process Hub is an Azure-only feature
(multi-investigation aggregation requiring persistence per ADR-072);
PWA is session-only by ADR-012. Confirmed during planning.

Phase 2 PR #2 of N.

Co-authored-by: ruflo <ruv@ruv.net>
jukka-matti added a commit that referenced this pull request Apr 27, 2026
Combines three sequenced PRs into one spec per feedback_full_vision_spec
memory:
- PR #1 (H1): team notes on state items — question / gemba / data-gap /
  decision kinds, persisted in ProcessHubInvestigationMetadata.stateNotes
- PR #2 (V2 follow-up): full EvidenceSheet rendering — refactors
  ProcessHubEvidenceContract to split countFor (sync) + loadFindingsFor
  (async), eliminates the synthetic-Finding cast from PR #99
- PR #3 (H2 launch): General Evidence Source for CSV/Excel — adds
  GENERIC_TABULAR_PROFILE to DATA_PROFILE_REGISTRY, mapping confirmation
  UI in ProcessHubEvidencePanel, cadence metadata

Resolves both prior open questions inline:
- Evidence contract split (countFor + loadFindingsFor + onChipClick +
  onFindingSelect — cleaner than overloading findingsFor sync/async)
- Mapping UX explicit confirmation (matches operating-model § "analyst
  confirms mappings" language)

Updates spec index, marks the parent V2 actionable-panel spec as
Delivered (PRs #98 #99).

Co-Authored-By: ruflo <ruv@ruv.net>
jukka-matti added a commit that referenced this pull request Apr 27, 2026
Sequenced TDD breakdown for 3 PRs:
- PR #1: team notes on state items (~250-350 LOC, 8 tasks). New
  ProcessStateNote types in core, ProcessHubInvestigationMetadata
  extension, ProcessHubNotesContract on the panel, StateItemNotesDrawer
  in apps/azure, Dashboard wiring via useStorage round-trip.
- PR #2: full EvidenceSheet rendering (~300-400 LOC, 5 tasks). Refactors
  ProcessHubEvidenceContract to split countFor (sync) + loadFindingsFor
  (async); EvidenceSheet bottom sheet; Dashboard owns sheet state +
  async load via useStorage; eliminates synthetic-Finding cast from PR
  #99.
- PR #3: General Evidence Source for CSV/Excel (~600-800 LOC, 4 tasks).
  GENERIC_TABULAR_PROFILE in DATA_PROFILE_REGISTRY; profile picker UI;
  mapping confirmation form; cadence selector (5 actual EvidenceCadence
  values); telemetry on save.

Three implementation reality notes flagged at top:
1. Actual DataProfileDefinition signature differs from spec sketch
   (single 'label' field; detect takes only rows; confidence is
   'high'/'medium'/'low' enum not number).
2. EvidenceCadence enum lacks 'monthly' — use existing 5 values.
3. Spec back-link upgrades to Markdown link in PR #1 Task 7.

Co-Authored-By: ruflo <ruv@ruv.net>
jukka-matti added a commit that referenced this pull request Apr 28, 2026
…d telemetry

The Phase 3 spec's telemetry table specified payload {hubId, responsePath,
lens, evidenceCount} but the implementation omitted evidenceCount.
evidenceCount is the key engagement metric for the chip feature.

Threads count through the panel's onChipClick(item, hubId, count) so
Dashboard can include it in safeTrackEvent without re-deriving.

Phase 3 PR #2, code-review followup.

Co-Authored-By: ruflo <ruv@ruv.net>
jukka-matti added a commit that referenced this pull request Apr 28, 2026
* refactor(ui): split ProcessHubEvidenceContract into countFor + loadFindingsFor

Replaces the synthetic-Finding placeholder pattern from PR #99 with a
clean separation of concerns:
- countFor (sync) — chip badge count, derived from rollup metadata
- loadFindingsFor (async) — fetches real findings for the sheet, only
  called when consumer wires it after chip click
- onChipClick(item) — telemetry signal, no findings arg
- onFindingSelect(item, finding) — sheet's selection callback

Sheet management stays on the consumer side (next task wires Dashboard).
Eliminates the 'as unknown as readonly Finding[]' cast and the synthetic-
placeholder generation entirely.

Existing chip tests rewritten for the new contract; 2 new tests added
(no-load-on-render guard + onFindingSelect contract presence).

Phase 3 PR #2, Task 2.

Co-Authored-By: ruflo <ruv@ruv.net>

* feat(azure): add EvidenceSheet bottom sheet for finding click-thru

Lightweight sheet listing findings (label + status badge + click-thru).
Renders nothing when item is null; loading state when findings is null;
empty state for zero findings. Esc key, click-outside, and close button
all fire onClose.

Phase 3 PR #2, Task 3.

Co-Authored-By: ruflo <ruv@ruv.net>

* feat(azure): wire EvidenceSheet with lazy finding load on chip click

Replaces PR #99's synthetic-Finding placeholder pattern with a real
async load through the existing useStorage().loadProject() chain.

ProcessHubReviewPanel:
- countFor derives chip count from ProcessHubInvestigationMetadata.findingCounts
  (same arithmetic as the previous synthetic-placeholder length)
- loadFindingsForItem / onChipClick / onFindingSelect pass-through to Dashboard
- removes the synthetic Finding[] cast and TODO(evidence-sheet-pr) comment
- removes safeTrackEvent import (no longer needed in this component)

Dashboard:
- sheetState managed at Dashboard level (item + hubId + findings | null)
- handleChipClick: fires telemetry, opens sheet in loading state, async-loads
  via loadProject() chain, applies findings with a race guard
- handleFindingSelect: fires telemetry, closes sheet, navigates via existing
  onOpenProject + best-effort URL hash for finding deep-link
- EvidenceSheet rendered at Dashboard level (sibling of StateItemNotesDrawer)

Telemetry: process_hub.evidence_sheet_{opened,finding_clicked} with non-PII
payloads (hubId from rollup.hub.id, lens, responsePath, findingStatus enum
in finding-click event). No PII per ADR-059.

Phase 3 PR #2, Task 4.

Co-Authored-By: ruflo <ruv@ruv.net>

* fix(azure): drop dead URL-hash guard in handleFindingSelect

The guard `window.location.hash !== '#finding-${id}'` (with `#`) compared
against an assignment without `#` — the comparison was always false so
the guard never short-circuited. Assignment is idempotent in browsers
anyway; just drop the guard.

Phase 3 PR #2, code-review followup.

Co-Authored-By: ruflo <ruv@ruv.net>

* fix(azure): include evidenceCount in process_hub.evidence_sheet_opened telemetry

The Phase 3 spec's telemetry table specified payload {hubId, responsePath,
lens, evidenceCount} but the implementation omitted evidenceCount.
evidenceCount is the key engagement metric for the chip feature.

Threads count through the panel's onChipClick(item, hubId, count) so
Dashboard can include it in safeTrackEvent without re-deriving.

Phase 3 PR #2, code-review followup.

Co-Authored-By: ruflo <ruv@ruv.net>

---------

Co-authored-by: ruflo <ruv@ruv.net>
jukka-matti added a commit that referenced this pull request May 4, 2026
…g) (#121)

* docs: mark layered-process-view-v1 plan delivered

V1 component, FrameView swaps (PWA + Azure), and doc updates (ADR-070,
methodology.md, mental-model-hierarchy.md, llms.txt) all shipped via
production-line-glance C2 (merged 2026-04-29). Plan frontmatter was
never promoted; flipping deferred → delivered.

Co-Authored-By: ruflo <ruv@ruv.net>

* docs: consolidate product vision into one canonical spec

Adds docs/superpowers/specs/2026-05-03-variscout-vision-design.md as the
canonical product vision. Supersedes the 2026-04-27 operating-model and
product-method-roadmap specs (moved to docs/archive/specs/ with
status: superseded + forward pointer). methodology.md gets a
forward-pointer banner and survives as longer-form companion. All
inbound + outbound cross-refs updated; specs/index.md rows show
status: Superseded.

Vision thesis: "the map is the product" — Process Hub IS its logic map;
one continuous canvas (DAG with branch + join + two-level nesting +
context propagation) replaces the FRAME river-SIPOC + LayeredProcessView
+ LayeredProcessViewWithCapability stack; cards-with-mini-charts per
step + drill-down panel + mode lenses replace the separate Analysis tab;
"tributary" / "CTS" jargon retired. Engine and data model survive.

10 canvas commitments in spec section 3.3 are load-bearing. 11 open
questions in section 8 carry brainstorm defaults that need explicit
confirmation before implementation plans are written.

Decision-log pinned under Replayed Decisions (2026-05-03).

In-flight plan reconciliation (frontmatter status flips):
- delivered: production-line-glance C1/C2/charts (PRs #105/#106/#107),
  actionable-current-process-state-panel (PR #98),
  phase-3 H1/H2 (PRs #100/#101/#102)
- in-progress (corrected): coscout-intelligence-architecture,
  question-driven-eda-2-handoff, multi-level-scout-v1
- unchanged: phase-6-implementation-plan (deferred), investigation-wall
  (in-progress)

Brainstorm transcript: ~/.claude/plans/i-would-like-to-composed-rose.md.

Co-Authored-By: ruflo <ruv@ruv.net>

* docs: lock vision §8 decisions; canvas replaces Frame+Analysis tabs

Walk-through resolved 11 brainstorm-default markers in the 2026-05-03
vision spec §8, plus a new Q0 ("tab vs canvas scaffold") that emerged
during journey mapping. Headlines:

- Q0: Canvas eats Frame + Analysis tabs. Investigation / Improvement
  / Report keep their own surfaces. Wall is dual-home (destination
  + canvas overlay). JourneyPhase retires as a top-level nav primitive.
- Q1: Drill-down is a modern floating overlay anchored to the clicked
  card with blurred-canvas backdrop (overrides spec's "side-panel
  slides from right" default — that conflicted with the locked C3
  supersession of CoScout's right-rail claim).
- Q5: No CoScout map drafting in V1; manual click/drag/connect canvas
  authoring is the path (overrides spec default).
- Q7: Hard cutover, no migration window — no users yet to preserve.
- Q8: PWA gets local Hub-of-one with IndexedDB persistence; Azure
  adds cloud sync + multi-Hub + cadence + CoScout + team features.
- Q4 + Q11: Wall is dual-home; promoted hypotheses render as node
  markers, drafts as faint arrows.

Vision spec: §3.4, §5.2, §5.3, §5.4, §5.6, §5.7, §6, §7, §8 rewritten
in place; §8 replaced "open questions" with a "resolved decisions"
table; frontmatter status promoted draft → accepted.

ADR-070 (FRAME workspace): added 2026-05-03 supersession amendment
explicitly retiring FRAME as a top-level route; lists what survives
inside the Canvas vs what gets deleted in the same PR that ships it.

Decision-log: appended 2026-05-03 entry summarizing all 12 decisions
+ pointer to the §8 walkthrough plan.

Full rationale + spec/code follow-ups in
~/.claude/plans/lets-do-this-next-rustling-simon.md.

Co-Authored-By: ruflo <ruv@ruv.net>

* docs: §8 follow-ups — glossary, ADR amendments, roadmap re-tag

Smaller doc follow-ups triggered by the 2026-05-03 vision §8 resolution
(see commit f12e8b1 for the headline changes).

- docs/glossary.md (Q10): canonicalized as the single home for VariScout
  terminology. New "Process methodology terms" section (step / sub-step /
  column / input / output / outcome / branch & join / Process Hub) and
  a "Retired terms" table (tributary → factor; CTS → outcome; FRAME
  workspace → Canvas; Analysis tab → Canvas + lenses; Layered Process
  View → Canvas with lenses; etc) with replacements + retirement reasons.
- docs/01-vision/methodology.md (Q10): added forward pointer to
  glossary.md as the canonical terminology home; methodology stays as
  the longer narrative companion but stops re-defining terms.
- ADR-068 (Q3): added 2026-05-03 amendment formalizing modes and levels
  as orthogonal axes. Modes = which lens; levels = which slice (canvas
  pan/zoom). Level inferred from canvas state, not a separate picker.
  Refines (does not replace) the 2026-04-28 level-aware coaching
  amendment.
- ADR-059 (Q8): added 2026-05-03 amendment specifying PWA local
  Hub-of-one with IndexedDB persistence. Browser-tenant-only — Constitution
  P1 (browser-only processing) and P8 (no AI in free tier) preserved.
  Schema scope listed for the FRAME canvas detail spec to inherit.
- product-method-roadmap-design.md (Q6): added explicit "this is
  sequencing, not destination" header. Status was already superseded;
  the new framing tells stakeholders to read the vision spec first and
  consult this doc only for delivery-order intent.

docs:check green. No broken cross-refs, no orphans, frontmatter valid.

Co-Authored-By: ruflo <ruv@ruv.net>

* docs: add framing-layer design spec (Spec 1 of canvas-detail decomposition)

First of five canvas-detail specs decomposed from the 2026-05-03 vision
§8 walkthrough. Covers everything BEFORE canvas authoring proper —
Hub creation, data ingestion, investigation entry, multi-source join,
defect anchoring, Pareto integration, and the three composable canvas
filter states.

Two-layer model:
- Hub-level (durable): process goal narrative + outcome measure(s)
  + specs + primary scope dimensions
- Investigation-level (episodic): Issue → Question → CTP→CTQ
  Hypothesis → Evidence → Finding

Mode B (first-time Hub creation):
- Stage 1: free-text goal + scaffold chips (Purpose / Customer / What
  matters)
- Stage 2: paste/upload (existing UX)
- Stage 3: outcome confirmation with inline distribution + data quality
  + per-candidate inline specs (no σ-based suggestions — specs are
  customer-driven) + primary scope dimensions sub-step
- Stage 5: investigation entry as floating modal with skip-path →
  observation-triggered EDA

Mode A (reopening existing Hub):
- A.1: reopen, no new data → straight to canvas
- A.2-paste: match-summary card with timeline preview + 2-axis
  classifier (source × temporal); blocks on overlap and different-grain
- A.2-evidence-source: background ingestion with "X new snapshots ↑"
  indicator (Azure only — PWA Hub-of-one has no cloud sync per Q8)

Multi-source via shared keys: Hub spine = process line; multiple
sources joined via lot_id / batch_id / part_id; per-source provenance;
per-source independent timelines (V1).

Defect data + Pareto: multi-anchor (per-step rejects + outcome);
canvas-attached Pareto with two pickers (group-by × weighted-by);
Y-axis adapts to active mode lens (count / cost / time / Cpk gap /
%OOS / ...); Pareto-bar selection becomes canvas-wide scope filter
with "Make this the investigation scope" promote-to-investigation.

Three composable canvas filter states (time-window / scope /
Pareto-grouped) compose declaratively without new aggregation
primitives. ADR-073 holds: per-(node × context-tuple × scope) buckets
stay heterogeneity-aware.

Engine reuse: detectColumns() + inferMode() + validateData()
+ suggestNodeMappings + TimelineWindow + ParetoChart + StepErrorPareto
+ statusForCpk + investigation entities all already shipped. Almost
no new infrastructure required.

Spec is 638 lines, 16 sections including verification criteria.
Indexed at docs/superpowers/specs/index.md.

Inherits Q0 + Q1–Q11 anchors from §8 walkthrough at
~/.claude/plans/lets-do-this-next-rustling-simon.md.

Sibling specs (deferred): Spec 2 manual canvas authoring, Spec 3
cards / drill-down / mode lenses, Spec 4 canvas overlays + Wall sync,
Spec 5 IndexedDB persistence schema.

Co-Authored-By: ruflo <ruv@ruv.net>

* docs: revise Q8 — PWA persistence opt-in; .vrs files = shareable training scenarios

Walking back the original Q8 wording ("PWA = local Hub-of-one with
IndexedDB persistence" — auto-on) to Option 4 hybrid: session-only
by default; opt-in via "Save to this browser" → IndexedDB-backed
Hub-of-one; .vrs file export/import always available.

Strategic reframe: PWA serves four personas (LSSGB students, demos,
casual analysts, AND trainers authoring scenarios). Trainers package
datasets + Hub state + sample investigations into a .vrs bundle and
share via LMS / email; students import to start from a prepared
training state. .vrs becomes the scenario-distribution format,
positioning PWA as the methodology-teaching surface.

Persistence is now explicit consent per persona — training students
opt in once and auto-save; demo users skip; privacy-conscious users
export to file; trainers export+share. Constitution P1 (browser-only
processing) and P8 (no AI in free tier) preserved. Companies still
use Azure tier for centralized + secure persistence per ADR-059.

Updates:
- vision spec §7 tier paragraph rewritten + §8 Q8 row updated
- framing-layer spec §15 V1 scope adds opt-in Save-to-browser +
  .vrs export/import + IndexedDB-loaded-post-opt-in; §14 anchors
  table Q8 row revised
- decision-log §1 entry added: "Q8 revised — PWA persistence opt-in"
  with strategic rationale (training scenarios; trainer persona;
  no surprise persistence on shared computers)
- apps/pwa/CLAUDE.md hard rule updated from "no persistence" to
  "session-only by default; opt-in IndexedDB allowed; .vrs
  import/export for trainer-shared scenarios"

docs:check green.

Co-Authored-By: ruflo <ruv@ruv.net>

* plan: Framing Layer V1 Slice 1 — Foundation (16 tasks, TDD bite-sized)

First implementation plan from the framing-layer spec.

Slice 1 scope (smallest end-to-end):
- Mode B Stages 1–3 + canvas first paint (PWA + Azure)
- Mode A.1 reopen (Azure always; PWA only if opted in)
- PWA opt-in IndexedDB persistence (Q8-revised Option 4)
- PWA .vrs file export/import (round-trip; trainer scenarios)
- ProcessHub schema extension (processGoal, outcomes,
  primaryScopeDimensions)
- Goal-context biased outcome detection
- Multi-outcome validateData refactor
- Inline per-candidate spec editor (no σ-based suggestions)
- Characteristic-type-aware spec defaults
- Primary scope dimensions auto-suggest + multi-select
- Graceful degradation banner (no goal-keyword match)

16 tasks, TDD bite-sized (failing test → run + fail → implement
→ run + pass → commit). Task 0 locks 5 load-bearing decisions
in a companion file. Subagent-driven default execution per
feedback_subagent_driven_default; Sonnet workhorse.

Out of scope (later slices):
- Slice 2: Stage 5 modal + Mode A.2-paste + A.2-evidence-source
- Slice 3: Multi-source via shared keys
- Slice 4: Defect anchoring + Pareto on canvas

Plan referenced from:
- docs/decision-log.md §4 Session Backlog (queued row added)
- docs/superpowers/specs/2026-05-03-framing-layer-design.md
  (Implementation plans section added — lists all 4 V1 slices)

docs:check green; 471 docs frontmatter-valid.

Co-Authored-By: ruflo <ruv@ruv.net>

* plan: expand Tasks 6–15 to full TDD step-by-step

Per writing-plans skill 'no placeholders' rule: each task in a
plan must be self-contained because subagent-driven execution
reads tasks out of order in fresh subagents per task. Original
slice-1 plan had Tasks 1–5 fully step-by-step but Tasks 6–15
sketched ('follow the same TDD shape') — violated the rule.

Expanded all 10 sketched tasks to the same TDD pattern as Tasks
1–5: failing test code → run + fail expected output →
implementation code → run + pass expected output → commit
message. Plan grew 1135 → 3272 lines.

Tasks now self-contained:
- 6: OutcomeCandidateRow (6 RTL tests)
- 7: characteristicTypeDefaults (7 tests)
- 8: suggestPrimaryDimensions + selector UI (9 tests)
- 9: OutcomeNoMatchBanner (3 RTL tests)
- 10: GoalBanner + OutcomePin (8 RTL tests)
- 11: .vrs file format + export/import (5 tests)
- 12: PWA Dexie hubRepository (7 tests)
- 13: SaveToBrowserButton + VrsExport/Import (6 tests)
- 14: PWA Mode B E2E + Mode A.1 RTL (3 tests)
- 15: Azure HubCreationFlow + ProcessHubView GoalBanner (2 tests)

Plan ready for superpowers:subagent-driven-development.
docs:check green.

Co-Authored-By: ruflo <ruv@ruv.net>

* plan: lock 5 decisions for framing-layer V1 slice 1

D1: AnalysisBrief unchanged; new OutcomeSpec type
D2: PWA persistence opt-in via 'Save to this browser'
D3: validateData multi-outcome refactor
D4: Goal-context biasing is deterministic keyword extraction
D5: Mode A.1 reopen gated by IndexedDB opt-in flag (no PWA Hub list)

* feat(core): add framing-layer fields to ProcessHub

processGoal: string narrative (Hub-level durable)
outcomes: OutcomeSpec[] (CTQs in plain language)
primaryScopeDimensions: string[] (prominent picker dimensions)

OutcomeSpec includes characteristicType (nominalIsBest /
smallerIsBetter / largerIsBetter) — drives spec-input UI per
framing-layer spec §5.3. Specs are customer-driven; no σ-based
suggestions per Q8 / spec §3.3.

* feat(core): extractHubName utility

Extracts a short Hub name (≤50 chars, word-boundary truncated)
from the first sentence of a goal narrative.

Used by Stage 1 HubGoalForm to auto-populate the Hub name field
on goal-narrative confirm.

* fixup! feat(core): extractHubName utility

Remove unnecessary .trimEnd() — plan's slice + lastIndexOf + final trim
already handles the space-at-boundary case correctly without dropping
an extra word.

Co-Authored-By: ruflo <ruv@ruv.net>

* feat(core): goal-context biasing in detectColumns

Optional DetectColumnsOptions.goalContext threads the user's
goal narrative through to outcome ranking. Tokenizes the
narrative (lowercased, stopwords removed), computes per-column
keyword overlap with the goal, adds a 0.5-weight bonus on top
of existing scoring.

Implements framing-layer spec §3.1: goal narrative biases
deterministic detection at Stage 3. Deterministic — no AI
(per Q5). Backward-compatible (option is optional).

* feat(parser): refactor validateData to accept string[] outcomeColumns

Signature changed from `(data, outcomeColumn: string | null)` to
`(data, outcomeColumns: string[])`. A row is excluded when ANY listed
outcome column is invalid. New `perOutcome: Record<string, PerOutcomeQuality>`
field on DataQualityReport exposes per-column valid/invalid/missing counts.
All six existing call sites updated; existing tests migrated to array API;
no backward-compat overload (D3, feedback_no_backcompat_clean_architecture).

Co-Authored-By: ruflo <ruv@ruv.net>

* feat(ui): HubGoalForm component (framing layer Stage 1)

Free-text textarea with three scaffold chips ('+ Purpose',
'+ Customer', '+ What matters') that insert labeled prompt
chunks into the narrative on click. Optional 'See examples'
link surfaces three anonymized goal narratives. Skip-framing
path supported.

Implements framing-layer spec §5.1 — Option C 'free-text +
scaffold chips' shape locked during brainstorm.

* feat(ui): OutcomeCandidateRow with inline per-candidate specs

Stage 3 horizontal candidate row layout: radio + name +
sparkline + (when selected) inline spec inputs + quality stack
+ match confidence. LSL/USL placeholders say 'from customer
spec' (no σ-based suggestions per Q8/Q2). LSL disabled for
smallerIsBetter; USL disabled for largerIsBetter.

Adds @variscout/core/processHub sub-path export so consumers can
reach the new CharacteristicType / OutcomeSpec types without
colliding with the unrelated CharacteristicType in core/types.ts.

Implements framing-layer spec §5.3.1.

Co-Authored-By: ruflo <ruv@ruv.net>

* feat(core): characteristic-type-aware spec defaults

inferOutcomeCharacteristicType: case-insensitive name-keyword
detection (defect/reject/scrap/fail/error/fault →
smallerIsBetter; yield/uptime/throughput/recovery/efficiency →
largerIsBetter; default nominalIsBest). Renamed from the plan's
inferCharacteristicType to avoid collision with the existing
spec-limit-based inferCharacteristicType in core/types.ts.

defaultSpecsFor: returns target=mean for nominalIsBest;
target=0 for smallerIsBetter; no target for largerIsBetter.
cpkTarget=1.33 (literature default) across the board. No
LSL/USL suggestions — those are customer-driven (per Q8/Q2).

7 tests in packages/core/src/specs/__tests__/characteristicTypeDefaults.test.ts.
Re-exported at root barrel as inferOutcomeCharacteristicType,
defaultSpecsFor, DataStats.

Co-Authored-By: ruflo <ruv@ruv.net>

* feat: PrimaryScopeDimensions auto-suggest + selector UI

suggestPrimaryDimensions filters columns by cardinality (3-50)
+ name keyword (id/lot/batch/product/customer/shift/operator/
machine/supplier/sku/plant/line/station). High-cardinality
columns (>50 levels) flagged as 'join key, not Pareto
candidate'.

PrimaryScopeDimensionsSelector pre-checks suggested columns;
user confirms or overrides; skippable. Implements framing-
layer spec §3.4 and §5.3.2.

Co-Authored-By: ruflo <ruv@ruv.net>

* feat(ui): OutcomeNoMatchBanner graceful degradation

Renders when max(candidate.matchScore) < 0.30 (cryptic columns
or vague goal). Surfaces rename affordance, free-text 'I
expected the outcome to be' note, and skip-outcome path. Hub
records the user's pick for future detection (slice 1 stub;
full learning loop in Spec 5).

Implements framing-layer spec §5.3.3.

* feat(ui): GoalBanner + OutcomePin canvas first-paint components

GoalBanner renders Hub.processGoal at top of canvas;
click-to-edit opens textarea with Save / Cancel; onChange
callback to parent. Hides itself when goal is empty.

OutcomePin shows Cpk badge when specs are set + n>=10; falls
back to 'mean ± σ + n' + '+ Add specs' chip when specs absent;
shows 'Trust pending' when specs set but n<10. Per Q2 fallback
rule (framing-layer spec §5.2) and sample-size honesty
(vision §2.3).

* feat(core): .vrs file format + export/import (round-trip tested)

VRS_VERSION='1.0'. VrsFile shape: version, exportedAt, hub,
optional rawData, optional metadata (exportSource pwa|azure +
appVersion).

vrsExport(hub, rawData?, metadata?) → JSON string (pretty,
indent 2).
vrsImport(json) → VrsFile with version validation + clear
error messages on mismatch. Hub-only export supported (rawData
optional, useful for canvas-without-data sharing).

Round-trip preserves Hub + rawData via JSON serialization.
.vrs files double as shareable training scenarios per
Q8-revised.

Co-Authored-By: ruflo <ruv@ruv.net>

* feat(pwa): Dexie hubRepository for opt-in Hub-of-one persistence

New PwaDatabase (Dexie v1) with two tables: hubs (single-row
Hub-of-one constraint) + meta (opt-in flag).

hubRepository API: getOptInFlag / setOptInFlag (auto-clears
Hub on false) / saveHub (overwrites single row) / loadHub
(returns null if absent) / clearHub.

Per Q8-revised: Dexie loaded only after explicit opt-in via
'Save to this browser' affordance (Task 13). Default behavior
unchanged from today (session-only). dexie + fake-indexeddb
added as dependencies.

Co-Authored-By: ruflo <ruv@ruv.net>

* feat(pwa): Save-to-browser opt-in + .vrs export/import buttons

SaveToBrowserButton: shows 'Save to this browser' when not
opted in; clicking opts in + persists Hub. Once opted in,
auto-saves on Hub change. Button switches to 'Saved · Forget'
— click + confirm clears persistence (calls setOptInFlag(false)
which auto-clears Hub).

VrsExportButton: serializes current Hub + data via vrsExport,
downloads as <hub-name>.vrs (sanitized).

VrsImportButton: file picker; reads file → vrsImport →
emits onImport({ hub, rawData }) for parent to consume.
Per Q8-revised hybrid persistence (Option 4).

* feat(pwa): Mode A.1 reopen wiring + SessionProvider scaffold

SessionProvider holds current Hub + rawData in React Context (in-memory;
persistence via opt-in hubRepository).

App.tsx: on mount, getOptInFlag → if true, loadHub() and seed sessionHub.
GoalBanner renders above main content when sessionHub.processGoal is set,
so a Mode A.1 reopen surfaces the saved Hub goal immediately. RTL test
verifies both branches: opt-in false → HomeScreen; opt-in true + saved
Hub → canvas with goal banner restored from IndexedDB.

Mode B end-to-end (paste → goal → mapping → canvas first paint with
OutcomePin per outcome) requires the ColumnMapping refactor that is
out of scope for slice 1; the Playwright spec is checked in as .skip
to be re-enabled when Stage 1/3 routing lands inside App.tsx.

* feat(pwa): inject HubGoalForm Stage 1 into Mode B paste flow

After paste analyze, before ColumnMapping, render HubGoalForm so
the user states the process goal. On confirm, store narrative in
sessionStore. On skip, sentinel '' marks the Stage 1 step done
without a narrative. ColumnMapping now waits for goalNarrative !==
null.

ColumnMapping internals unchanged — Stage 3 refactor (using
OutcomeCandidateRow / PrimaryScopeDimensionsSelector /
OutcomeNoMatchBanner) ships in slice 2. Hub.processGoal is set
at ColumnMapping confirm if narrative was provided; outcomes[]
and primaryScopeDimensions are left for slice 2 (TODO marker in
handleMappingConfirmWithGoal).

Co-Authored-By: ruflo <ruv@ruv.net>

* feat(azure): mount GoalBanner above Hub tabs + Dexie v7 no-op

ProcessHubView renders <GoalBanner goal={hub.processGoal}>
above the existing tab container — Mode A.1 reopen surfaces
the saved process goal immediately on Hub load (Azure tier
persists Hub-level state via Dexie always; no opt-in needed).

Dexie schema bumped 6 -> 7 as a no-op version; the new
ProcessHub fields (processGoal, outcomes,
primaryScopeDimensions) added in Task 1 are optional
TypeScript additions that Dexie stores without schema
migration. (Plan said v4 -> v5; the actual Azure schema was
already at v6, so the bump lands at v7.)

GoalBanner is mounted read-only for slice 1 because
ProcessHubView does not currently receive a Hub-update
callback in its props; wiring onChange is deferred to slice 2
alongside HubCreationFlow.

HubCreationFlow component (Stage 1 -> Stage 2 -> Stage 3 ->
built Hub) and the Dashboard "+ New Hub" button are deferred
to slice 2 — the plan's Stage3Mapping implementation is
sketch-only and the full ColumnMapping refactor required to
wire OutcomeCandidateRow / PrimaryScopeDimensionsSelector /
OutcomeNoMatchBanner is out of scope for slice 1 (mirrors the
slice-1 PWA Task 14 follow-up).

Co-Authored-By: ruflo <ruv@ruv.net>

* docs: framing-layer spec status draft -> active

Spec is the active working design. Slice 1 implements its
foundation; Stage 3 ColumnMapping refactor + multi-source +
defect anchoring continue across slices 2-4.

Decision-log session-backlog row already reflects in-flight
status (commit d49cbfe).

* docs: update slice-1 row with delivery state + slice-2 deferrals

Slice 1 row → in-flight with the foundation enumeration and
explicit slice-2 deferrals (Stage 3 ColumnMapping refactor,
canvas first-paint OutcomePin, button mounting in PWA UI,
Azure HubCreationFlow, Mode B E2E). Per final-reviewer
finding (Important #2): Save-to-browser + .vrs Export/Import
buttons are tested + scaffolded but currently unmounted —
slice 2 will surface them in the PWA chrome.

---------

Co-authored-by: ruflo <ruv@ruv.net>
jukka-matti added a commit that referenced this pull request May 6, 2026
* data-flow F1+F2 P5.1: AzureHubRepository skeleton + composition root

Adds AzureHubRepository implementing HubRepository from @variscout/core/persistence.
Dispatch short-circuits HUB_PERSIST_SNAPSHOT to saveProcessHubToIndexedDB (bootstrap);
all other action kinds throw explicit P5.2/P5.3 not-yet-implemented error. Read APIs
wire against existing Azure Dexie tables (processHubs, evidenceSources, evidenceSnapshots,
evidenceSourceCursors); F3-pending entities (investigations, findings, questions,
causalLinks, suspectedCauses) are stubbed. Module-scoped azureHubRepository singleton
mirrors PWA composition-root pattern. apps/azure/CLAUDE.md updated with
persistence-boundary invariant documenting R12+R13 exceptions.

Co-Authored-By: ruflo <ruv@ruv.net>

* data-flow F1+F2 P5.1 review fixes: hubs.list tombstone filter + multi-hub outcomes test + dispatch error test

- hubs.list() now filters h.deletedAt === null; hubs.get stays unscoped (comment added)
- outcomes.get has O(n hubs) comment noting F3 normalization will remove the scan
- AzureHubRepository.read.test: hubs.list tombstone test + multi-hub outcomes.get test
- AzureHubRepository.test: HUB_PERSIST_SNAPSHOT error propagation test
- Fix 4: corrected misleading fake-indexeddb comment ("kept at line 1" → "must be the first import statement")

Co-Authored-By: ruflo <ruv@ruv.net>

* data-flow F1+F2 P5.2: Azure cascade helper with Dexie transaction

Adds cascadeArchiveDescendants(parentKind, parentId, archivedAt) in
apps/azure/src/persistence/cascadeArchive.ts. Uses transitiveCascade()
from @variscout/core/persistence; wraps all Dexie writes in a single
'rw' transaction covering evidenceSnapshots, evidenceSources,
evidenceSourceCursors, and processHubs. Per-kind stubs with F3 comments
for investigation/finding/question/causalLink/suspectedCause/rowProvenance/
canvasState (no Azure tables today). Outcome cascade explicitly deferred
to P5.3 per-action handler (hub blob mutation). Evidence source cursor
hub-range query uses compound PK [hubId+sourceId] between(). 10 new tests
covering: evidenceSource→cursor cascade, hub multi-table cascade,
investigation no-op, rollback, idempotency, empty-descendants. Barrel
updated to re-export the helper.

Co-Authored-By: ruflo <ruv@ruv.net>

* data-flow F1+F2 P5.2 review fixes: cascade JSDoc + rollback comment + fan-out test

- Fix 1: add ## Atomic call pattern (P5.3+) section to cascadeArchiveDescendants
  JSDoc prescribing the outer-transaction wrapping pattern P5.3 must use to
  keep parent-row update + descendant cascade atomic; explains Dexie 4 zone reuse.
- Fix 2: replace hedge comment in rollback test with confident pass-confirmation
  statement — rollback path verified green at P5.2 baseline (1098 tests).
- Fix 3: add cursor2 for src2 in the hub multi-table cascade test to cover the
  fan-out path (hub → both evidenceSource cursors via compound key-range scan).

Co-Authored-By: ruflo <ruv@ruv.net>

* data-flow F1+F2 P5.3: Azure per-action handlers + applyAction module

Implements all HubAction handlers in a new applyAction.ts module (Option B):
- Hub-blob mutations (HUB_UPDATE_GOAL, HUB_UPDATE_PRIMARY_SCOPE_DIMENSIONS,
  OUTCOME_ADD, OUTCOME_UPDATE, OUTCOME_ARCHIVE) — read-modify-write via
  saveProcessHubToIndexedDB.
- Direct Dexie table writes (EVIDENCE_ADD_SNAPSHOT, EVIDENCE_ARCHIVE_SNAPSHOT,
  EVIDENCE_SOURCE_ADD, EVIDENCE_SOURCE_UPDATE_CURSOR, EVIDENCE_SOURCE_REMOVE).
- EVIDENCE_SOURCE_REMOVE atomically wraps cascade + parent soft-delete in a
  single db.transaction; outer table list is a superset of cascadeArchiveDescendants'
  internal transaction to satisfy Dexie zone propagation.
- Session-only kinds (INVESTIGATION_*, FINDING_*, QUESTION_*, CAUSAL_LINK_*,
  SUSPECTED_CAUSE_*) — documented no-ops with F3 comment.
- Canvas kinds — documented no-ops with HUB_PERSIST_SNAPSHOT-flow comment.
- TypeScript exhaustiveness via assertNever() ensures compile-time completeness.

AzureHubRepository.dispatch now delegates to applyAction after the
HUB_PERSIST_SNAPSHOT short-circuit.

Adds 73 new tests (1098 → 1171). Adds sustainment-deferral note to
apps/azure/CLAUDE.md Invariants section.

Co-Authored-By: ruflo <ruv@ruv.net>

* data-flow F1+F2 P5.3 review fixes: parent-update rollback test + @internal barrel + idempotency notes

Co-Authored-By: ruflo <ruv@ruv.net>

* data-flow F1+F2 P6: Azure call-site migration to dispatch (storage facade + cursor sync)

Migration A: replace saveProcessHubToIndexedDB, saveEvidenceSourceToIndexedDB,
saveEvidenceSnapshotToIndexedDB in the three StorageProvider save methods with
azureHubRepository.dispatch(HUB_PERSIST_SNAPSHOT | EVIDENCE_SOURCE_ADD |
EVIDENCE_ADD_SNAPSHOT). Cloud-sync blocks unchanged. List/cache paths (lines 548,
595, 642) intentionally kept on direct localDb helpers (read-sync only).
Bootstrap save in listProcessHubs (line 548) left on direct call — it syncs cloud
→ local cache, not a hub-write dispatch path.

Migration B: replace db.evidenceSourceCursors.{get,put} in useEvidenceSourceSync
with azureHubRepository.evidenceSources.getCursor (Option B-1) and
dispatch(EVIDENCE_SOURCE_UPDATE_CURSOR). No direct Dexie usage remains in the file.

Tests: storage.test.ts — added db.processHubs mock for ensureDefaultProcessHubInIndexedDB;
added persistence mock for azureHubRepository.dispatch; added saveProcessHub /
saveEvidenceSource / saveEvidenceSnapshot tests asserting dispatch called with correct
action shapes. useEvidenceSourceSync.test.ts — replaced db.evidenceSourceCursors mock
with azureHubRepository mock; updated markSeen test to assert dispatch call shape.

Tests: 1173 → 1178 ✓ (5 new). Build: clean.

Co-Authored-By: ruflo <ruv@ruv.net>

* data-flow F1+F2 P6 review fix: tighten cloud-sync test mocks for evidence paths

Add hoisted mocks + vi.mock factory entries for all six evidence-blob
functions (listBlobEvidenceSnapshots, saveBlobEvidenceSnapshot,
updateBlobEvidenceSnapshots, listBlobEvidenceSources,
saveBlobEvidenceSource, updateBlobEvidenceSources). Previously the
saveEvidenceSnapshotToCloud path called undefined blob functions which
were silently swallowed, letting the cloud-sync assertion pass without
the blob calls ever firing. Tighten the existing snapshot online test
to assert exact dispatch shape (provenance: []) + blob function calls.
Add parallel online + cloud-sync test for saveEvidenceSource covering
dispatch shape and blob function calls. Tests: 1178→1179.

Co-Authored-By: ruflo <ruv@ruv.net>

* data-flow F1+F2 P7: ESLint dexie/db guard + dispatch-only docs

- P7.1: Update packages/stores, apps/pwa, apps/azure CLAUDE.md files to
  explicitly state the dispatch-only invariant (domain stores never import
  dexie directly; access via HubRepository / pwaHubRepository.dispatch /
  azureHubRepository.dispatch). Update "will add" references to past tense
  now that P7.2 delivers the rule. Enumerate R12+R13 exceptions clearly in
  each file.
- P7.2: Add ESLint no-restricted-imports rule in eslint.config.js blocking
  dexie package imports and **/db/schema glob imports outside the documented
  allow-list (persistence/, db/, wallLayoutStore.ts, azure services/storage
  + localDb + cloudSync + lib/persistence, test files). Smoke-tested: rule
  fires on ProcessHubEvidencePanel.tsx with clear actionable message; passes
  cleanly against current codebase (0 errors).
- P7.3: Confirmed pnpm lint is already a step in pr-ready-check.sh (no
  script change needed). pr-ready-check passes end-to-end.

Co-Authored-By: ruflo <ruv@ruv.net>

* data-flow F1+F2 P8.3 closeout: doc polish + decision-log + spec delivered

- Minor #1: add bootstrap cache-fill comment above storage.ts:548 for-loop
- Minor #2: R12 self-document comment on wallLayoutStore Dexie import
- Minor #3: fix plan frontmatter category (implementation-plan/audit → implementation)
- decision-log: F1+F2 closeout entry (what/why/deltas) + session backlog row
- spec: 2026-05-06-data-flow-foundation-design.md status active → delivered

Co-Authored-By: ruflo <ruv@ruv.net>

---------

Co-authored-by: ruflo <ruv@ruv.net>
jukka-matti added a commit that referenced this pull request May 8, 2026
8-task TDD-shaped plan executing the spec at
docs/superpowers/specs/2026-05-07-canvas-hypothesis-arrow-drawing-design.md.

Tasks (bottom-up):
1. useHypothesisDrawTool state machine + endpoint resolver (hooks)
2. activeCanvasTool field + auto-enable hypotheses overlay (hooks)
3. HypothesisDrawToolButton chrome component (ui)
4. HypothesisDraftPopover form (ui, hand-rolled positioning)
5. StepNodeMarker promoted-hypothesis pip (ui, Lucide Flag)
6. CanvasStepCard updates: replace badge, data-arrow-endpoint,
   gate click during draw
7. Canvas chrome integration: button + pointer handlers + rubber-band
   SVG + state-machine wiring through CanvasWorkspace
8. CanvasStepOverlay Remove button + investigations.md resolution
   + manual chrome walk steps

Plan-time deferrals locked: column resolution via card.metricColumn
(Risk #1); return-to-select after Save (Risk #2); hand-rolled
positioning, no new dep (Risk #5); Lucide Flag with status colors
(Risk #6).

Subagent-driven dispatch per master plan D6 + feedback_subagent_driven_default.
Sonnet for >=70% of dispatches; Opus for final review only.

Master plan section 4 8d entry updated with forward link to this plan.

Co-Authored-By: ruflo <ruv@ruv.net>
jukka-matti added a commit that referenced this pull request May 14, 2026
…leanup workstream) (#166)

* fix(8f-followup): delete legacy variscout-wall-layout Dexie DB on init

Closes 8f followup HIGH #3 — pre-8f users carried an orphan IndexedDB
forever after the wallLayoutStore → canvasViewportStore shape change.
Mirror PwaHubRepository's legacy-DB cleanup pattern. Tightens the
existing test that lied about asserting deletion.

Co-Authored-By: ruflo <ruv@ruv.net>

* refactor(8f-followup): migrate canvas UI strings to typed message catalogs

Closes 8f followup HIGH #5 — 47 hardcoded English strings across
SystemLevelView, CanvasLensPicker, MobileLevelPicker, NoFocalStepPrompt,
AuthorL3View, LocalMechanismView now route through MessageCatalog.
CANVAS_LENS_REGISTRY labels/descriptions translated at render time in
CanvasLensPicker via LENS_LABEL_KEY / LENS_DESC_KEY maps; the hooks
registry keeps English for non-UI consumers. Non-English locales receive
English placeholders pending a translation pass (TODO(i18n) comment).

Co-Authored-By: ruflo <ruv@ruv.net>

* fix(8f-followup): migrate Canvas empty-state to message catalog

Closes the i18n reviewer's flagged follow-up: Canvas/index.tsx:1042
rendered the lens registry's English label and a local
CANVAS_LEVEL_LABELS map as user-facing copy, bypassing i18n.

- Export LENS_LABEL_KEY from CanvasLensPicker for cross-component reuse
- Reuse canvas.mobile.{system,process,step} for level labels
- Add canvas.lensPicker.invalidAtLevel parameterized key (32 locales,
  English placeholder elsewhere per the catalog's translation pass plan)
- Drop CANVAS_LEVEL_LABELS + remove now-unused CANVAS_LENS_REGISTRY import

Co-Authored-By: ruflo <ruv@ruv.net>

* test(8f-followup): cover CanvasLensPicker lens × level predicate

Closes 8f followup LOW #20 — load-bearing CanvasLensPicker had no
dedicated test. 18 enabled/disabled cells (3 levels × 6 lenses) +
click-dispatch + aria-label assertions.

Co-Authored-By: ruflo <ruv@ruv.net>

* docs(8f-followup): refresh stale wallLayoutStore references in store comments

Closes 8f followup LOW #18 — viewStore.ts:140 + preferencesStore.ts:178
still mentioned wallLayoutStore in doc-strings after the PR1 rename to
canvasViewportStore.

Co-Authored-By: ruflo <ruv@ruv.net>

* docs(8f-followup): fix plan frontmatter category to allowed enum value

* refactor(8f-followup): extract getStepColumnAssignments to @variscout/core/frame

Closes 8f followup HIGH #2 — AuthorL3View's private focalStepColumns
helper duplicates business logic that should live in core/frame. The
helper now lives at packages/core/src/frame/stepColumns.ts with 6
unit tests; AuthorL3View imports it. Per ADR-074 amendment + ADR-081:
Canvas embeds owner-surface computation, doesn't re-derive.

Co-Authored-By: ruflo <ruv@ruv.net>

* fix(8f-followup): tie L1 specLimits to outcome's own measureSpecs entry

Closes 8f followup MEDIUM #8 — SystemLevelView trusted a flat specLimits
prop without ADR-073-anchored contract. Now accepts measureSpecs keyed by
column and derives from measureSpecs[map.ctsColumn] internally; old prop
renamed to specLimitsOverride (advisory/debug only, deprecated). Canvas
passes { [ctsColumn]: { usl, lsl, target, cpkTarget } } as measureSpecs.
Two regression tests assert the leak scenario: wrong-column measureSpecs
key produces '--' Cpk, not a silently wrong value.

Co-Authored-By: ruflo <ruv@ruv.net>

* refactor(8f-followup): replace LocalMechanismView's focalStepColumns duplicate

Same ADR-074 amendment violation that PR2 fixed in AuthorL3View. The
private helper now delegates to getStepColumnAssignments from
@variscout/core/frame (introduced in the prior commit), flattening the
structured result into the string[] this view needs.

Co-Authored-By: ruflo <ruv@ruv.net>

* docs(8f-followup): resolve lens × level matrix gap via spec amend

Closes 8f followup HIGH #4 via AMEND path (not expand). Git blame shows
both `performance` and `yamazumi` lenses were introduced with
`enabled: false` AND registry descriptions explicitly labeling them as
"Future ... lens" — intentional V2 placeholders, not bugs. Spec §10 was
over-promised at original ship.

- Spec §10 matrix amended: 6 cells marked `(V2 — deferred; lens not
  enabled in V1)` instead of pretending they ship enabled
- V2 expansion path documented inline
- investigations.md entry marked RESOLVED 2026-05-13 with rationale

Co-Authored-By: ruflo <ruv@ruv.net>

* feat(8f-followup): replace setViewportLevel throw with warn + no-op (4.4)

l3 without focalStepId now emits console.warn and returns the viewport
unchanged instead of throwing. fitToContent guards the same path.
Updated test asserts warn was called and state did not change.

Co-Authored-By: ruflo <ruv@ruv.net>

* refactor(8f-followup): co-locate level math constants in core/canvas/viewport (4.7)

Move FIT_TO_CONTENT_ZOOM_BY_LEVEL from canvasViewportStore into
@variscout/core/canvas/viewport.ts and re-export it through the barrel.
Add LOD_SNAP_BOUNDARIES (L2_OVERVIEW_LOW=0.5, L2_DETAIL_HIGH=1.8) for
the upcoming snap-to-LOD feature. Single source of truth for level math.

Co-Authored-By: ruflo <ruv@ruv.net>

* feat(8f-followup): enforce 6px click-vs-drag deadband via clickDistance(6) (4.3)

Adds .clickDistance(6) to the d3-zoom behavior in useCanvasViewportInput.
Pointer moves ≤5px are treated as clicks; ≥6px as drags. Matches spec §6.3.

Co-Authored-By: ruflo <ruv@ruv.net>

* chore(8f-followup): delete dead worldToWallSvg + document CanvasViewport (4.5/4.6)

worldToWallSvg was an identity function with no callers outside its own test;
deleted function and test. CanvasViewport is used in Canvas/index.tsx — added
JSDoc comment explaining its role so the seam is documented.

Co-Authored-By: ruflo <ruv@ruv.net>

* feat(8f-followup): snap-to-LOD on wheel-stop via d3-zoom end handler (4.2)

Adds a 'end' listener to the zoom behavior. When the user releases the wheel
with zoom in [0.3, 0.5) or [1.8, 2.0), the viewport eases back to 0.5 or 1.8
respectively over 150ms. Exports snapTarget() for unit testing. LOD_SNAP_BOUNDARIES
lives in @variscout/core/canvas/viewport alongside LOD_THRESHOLDS.

Co-Authored-By: ruflo <ruv@ruv.net>

* feat(8f-followup): real LOD cross-fade + d3-transition snap (4.1/4.2 final)

LODSwitcher now renders both outgoing and incoming renderers in stacked
absolute divs during a 150ms window, then unmounts the outgoing. Uses
useState+useEffect+setTimeout — no external animation library needed.

useCanvasViewportInput snap-to-LOD uses d3-transition via
selection.transition().duration(150).call(zoomBehavior.transform, ...).
Adds d3-transition + @types/d3-transition to @variscout/hooks deps.

Tests: 4 LODSwitcher tests assert dual-render during transition and
single-render after 150ms via fake timers.

Co-Authored-By: ruflo <ruv@ruv.net>

* feat(8f-followup): per-Hub canvas viewport blob helpers in blobClient

Closes 8f followup HIGH #1 part 1/2 — adds loadBlobCanvasViewport +
saveBlobCanvasViewport mirroring the updateBlobEvidenceSnapshots
ETag-conditional pattern. Per ADR-081 §2 (Azure = IndexedDB + Blob sync
with ETag per ADR-079) and ADR-079.

Also adds getLocalViewportUpdatedAt to @variscout/stores so the Azure
lifecycle hook can compare timestamps without reading Dexie directly.

Co-Authored-By: ruflo <ruv@ruv.net>

* feat(8f-followup): wire Azure canvas viewport lifecycle to Blob sync

Closes 8f followup HIGH #1 part 2/2 — useCanvasViewportLifecycle (Azure)
now rehydrates from Blob after Dexie cache, debounced-persists to both
Dexie and Blob with ETag, and treats precondition-failed as last-write-
wins per spec §11 with App Insights telemetry on the conflict path.

Co-Authored-By: ruflo <ruv@ruv.net>

* feat(8f-followup): expose 4 remaining response-path CTAs at L3 column granularity

Closes 8f followup MEDIUM #9 — LocalMechanismView previously only
exposed Quick Action. Spec §5.3.a lists 5 CTAs at column-mechanism
granularity (Quick Action / Focused Investigation / IP / Sustainment /
Handoff). Threaded the 4 step-level callbacks already on CanvasProps
through to LocalMechanismView; per-column button row added with new
i18n keys (8 new MessageCatalog keys across 32 locale files). Parent
callbacks are step-only; column is visible only within the card row.

Co-Authored-By: ruflo <ruv@ruv.net>

* feat(8f-followup): mobile L3 without focalStepId navigates to step-list

Closes 8f followup MEDIUM #10 — MobileLevelPicker previously called
setLevel('l2') before setZoom(2.5) as an explicit l2 redirect comment
implied. The final committed state was already l3 (setZoom(2.5) fires
inferLevel→l3), but the intent was undocumented. Updated comment to
clarify the atomicity: both calls run synchronously before React
re-renders, so the final state is l3 with no focalStepId, and canvas
renders NoFocalStepPrompt (the step-list surface) per spec §7.

Co-Authored-By: ruflo <ruv@ruv.net>

* perf(8f-followup): selector-scope canvasViewport subscribe in d3-zoom hook

Closes 8f followup MEDIUM #11 — useCanvasViewportInput previously
subscribed to the whole canvasViewportStore; every unrelated mutation
(setRailOpen, setViewMode, openChartCluster, etc.) fired
syncElementToStoreViewport (which has its own diff-check guard, but
still did needless work). Now tracks prevViewportRef and short-circuits
on reference equality of state.viewports[hubId] — sync is skipped
entirely when the hub's viewport slice hasn't changed. Test added:
setRailOpen → d3 element __zoom unchanged.

Co-Authored-By: ruflo <ruv@ruv.net>

* chore(8f-followup): rename canvasViewport STORE_LAYER to annotation-per-hub

Closes 8f followup LOW #15 — canvasViewportStore state is keyed by hubId
not projectId since the 8f shape change. The annotation-per-project
label was technically truthful (per-project umbrella, hub-keyed inside)
but invited confusion. Renamed to annotation-per-hub; layerBoundary
test + packages/stores/CLAUDE.md table updated. 'annotation-per-project'
is now in the reserved/unused set; 'annotation-per-hub' is live.

Co-Authored-By: ruflo <ruv@ruv.net>

* docs(8f-followup): mark 19 of 20 findings RESOLVED on followup branch

---------

Co-authored-by: ruflo <ruv@ruv.net>
jukka-matti added a commit that referenced this pull request May 16, 2026
…lar)

Project tab is active-IP-centric — shows ONE project's lifecycle (amendment spec §Decision summary #2). Rename key across all 32 locale files + MessageCatalog type + PWA nav consumer; update values to singular form for inflecting languages (en/fi/de/es/fr/it/pt/nl/pl/tr/sv/da/nb/cs/hu/ro/uk/sk/hr/bg/el/hi/ar/he) and native equivalents for non-inflecting languages (ja/ko/zh-Hans/zh-Hant/th/vi/id/ms). TDD: failing tests written first, confirmed red, then green.
jukka-matti added a commit that referenced this pull request May 16, 2026
* docs(plans): bite-sized sub-plan for PR-WV1-2 Improve workspace migration

* refactor(ui): route IPDetailPage + Charter ACL through canAccess

* docs(ui): explain CharterOverview empty-members escape

* feat(core): add migrateImprovementProjectMetadata + rename Handoff stage to Improve

Introduces migrateImprovementProjectMetadata (TDD, 4 tests) that
idempotently folds legacy team[] → wedge members[] at hydration time.
Exports from the improvementProject barrel.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(ui,apps): wire stage rename + metadata migration into hydration paths

Renames StageName / StageStateMap from handoff→improve; stage order is
now charter→approach→improve→sustainment. Updates IPDetailPage body render,
defaultActiveStage, and all affected tests. Wires
migrateImprovementProjectMetadata into Azure (hydrateHub) and PWA
(joinHub) at the lowest Dexie read seam.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(ui): add ImproveStage with canAccess-gated ActionItem tracker

Implements Task 2 of PR-WV1-2: creates ImproveStage component backed by
ActionItem list with edit-improve ACL gating, empty-state, add form, and
owner/due-date display; routes IPDetailPage 'improve' stage to ImproveStage
replacing the Handoff placeholder; adds onActionAdd/Update/Remove optional
props (no-op defaults) to IPDetailPageProps.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(ui): add ImproveStageAdvanced mounting PDCA primitives

Composes ImprovementContextPanel, IdeaGroupCard (per group), BrainstormModal
(modal-trigger owned by wrapper), PrioritizationMatrix, and WhatIfExplorer
into the Advanced workspace four-region layout.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(ui): add Advanced toggle on ImproveStage

Progressive disclosure per wedge spec §3.3 — simple action tracker by
default; Advanced button swaps in ImproveStageAdvanced (PDCA workbench).
Toggle visible to all roles; edit gating remains inside each view.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor(ui): fold Handoff close-logic into Sustainment closure

Wedge V1: the Handoff stage is retired; its close-project checklist
(control plan, training, cadence, process-owner acknowledgment + nudge)
is absorbed into SustainmentOverview as an optional closureInputs panel.
SustainmentSections gains a controlHandoff section in its sections view.

HandoffOverview and HandoffSections source files deleted; HandoffOverview
tests ported into SustainmentOverview test suite (4 new closure-panel
assertions). HandoffChecklistInputs type replaced with
SustainmentClosureInputs exported from SustainmentOverview.

IPDetailPage, both ProjectsTabViews (PWA + Azure), and App.tsx / Editor.tsx
callers updated: handoffInputs → closureInputs, onOpenLegacyHandoff removed.
Pre-existing whatIfMode:'basic' tsc error in ImproveStage absorbed and fixed
(fallback 'basic' → 'standard').

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* docs(specs): wedge V1 amendment — Improve top-level tab + Project singular

* docs(plans): bite-sized amendment plan for Improve-tab restoration

* refactor(ui): trim StageName to 3 values — drop 'improve' stage per amendment

Removes 'improve' from StageName, StageStateMap, and deriveStageState per the
2026-05-16 wedge amendment (Improve moves to top-level tab; Project detail shows
Charter / Approach / Sustainment only). Adds 'upcoming' to StageState union.

* refactor(ui): remove ImproveStage routing from IPDetailPage per amendment

Drop the 'improve' stage case, its render block, and the three onAction*
props from IPDetailPage — Improve is now a top-level tab, not a project
detail stage. Also remove the dead stages.improve branch from
defaultActiveStage and trim the matching test assertions.

* feat(ui): add NoActiveProjectGuidance empty state for Improve tab

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor(ui): move ImproveStage to Improve/; retire ImproveStageAdvanced; reuse ImprovementWorkspaceBase as Advanced view

Advanced toggle now renders ImprovementWorkspaceBase (production PDCA workbench)
instead of the skeleton ImproveStageAdvanced. Test mocks ImprovementWorkspaceBase
to keep the unit hermetic; runtime integration verified via --chrome browser walk.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(ui): add ImproveTabRoot orchestration component

Routes between NoActiveProjectGuidance empty state and ImproveStage
based on activeIP. Adds Improve/ barrel + re-exports from @variscout/ui.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(apps): wire ImproveTabRoot into PWA + Azure Improve tab

PWA: ImprovementView gains activeIP + onGoHome props; when activeIP is
threaded from App.tsx, renders ImproveTabRoot (NoActiveProjectGuidance
when null, action tracker when set). Fallback to pre-wedge ideas view
when activeIP prop not provided for backward compatibility.

Azure: Editor.tsx Improve section adds activeIP === null guard that
renders ImproveTabRoot empty state; active-IP case falls through to
existing ImprovementWorkspaceBase ideas workspace unchanged.

Action callbacks are console.warn stubs pending PR-WV1-3 persistence work.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(apps): route Azure Improve tab through ImproveTabRoot + tighten PWA prop contract

Azure Editor was gating <ImproveTabRoot> behind activeIP===null, letting active-IP
users fall through to the legacy <ImprovementWorkspaceBase> ideas view. Removed the
ternary — both branches are now a single unconditional <ImproveTabRoot> that handles
empty and active-IP states internally (mirrors PWA behaviour). Removed now-dead
imports and variables (ImprovementWorkspaceBase, ImprovementContextPanel,
WhatIfExplorerPage, PrioritizationMatrix, TrackView, DEFAULT_PRESETS, matrix axis
state, activeImprovementView/highlightedIdeaId store reads, scopedImprovementQuestions,
and unused orchestration destructure fields).

PWA ImprovementView: made activeIP, actions, onGoHome required (no optional shims);
deleted the pre-wedge fallback branch (ideas workspace + empty-ideas guard). App.tsx
call site updated to pass actions={[]} explicitly, drop the seven props that no longer
exist on the component, and remove the now-unused useImprovementOrchestration hook call.
Per feedback_no_backcompat_clean_architecture.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor(i18n): rename workspace.projects to workspace.project (singular)

Project tab is active-IP-centric — shows ONE project's lifecycle (amendment spec §Decision summary #2). Rename key across all 32 locale files + MessageCatalog type + PWA nav consumer; update values to singular form for inflecting languages (en/fi/de/es/fr/it/pt/nl/pl/tr/sv/da/nb/cs/hu/ro/uk/sk/hr/bg/el/hi/ar/he) and native equivalents for non-inflecting languages (ja/ko/zh-Hans/zh-Hant/th/vi/id/ms). TDD: failing tests written first, confirmed red, then green.

* docs(wedge): log PR-WV1-2 delivery + Improve-tab amendment

Records the Improve-tab-restore amendment under the 2026-05-16 wedge
entry: Improve restored as top-level verb tab, Project singular rename,
StageName trimmed to 3, ImproveTabRoot wired in both apps, deferred
items (b) + (d) from PR-WV1-1 closed, (a) + (c) still owed to
PR-WV1-3 / PR-WV1-5.

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
jukka-matti added a commit that referenced this pull request May 17, 2026
…log format + classify agent manifests

Audit gaps surfaced after yesterday's discipline shipment:
1. "One canonical home per concept" was buried as an anti-pattern; now stated affirmatively as Principle #2
2. Decision-log entry format was informal; now codified with edit-type vocabulary for Play 2c toolbox parsing
3. CLAUDE.md/AGENTS.md/llms.txt weren't classified in the doc-types table

Both strategy spec §2.7 and doc-discipline.md updated in parallel:

Core principles (in priority order):
1. Doc-type discipline
2. One canonical home per concept (Play 4 enforces)
3. Reader-first banners
4. Decision-log as temporal index

Wedge-amendment incident reframed as a simultaneous violation of principles 1+2+3,
making clear why all four need mechanical enforcement (Play 2b).

Doc types extended in the at-a-glance list: investigations + memory + agent manifests
added (was 5 types covered, now 8). Agent manifests get an explicit row in the
doc-discipline.md table noting they're the "first read" surface every agent dispatch
loads — keep tight, CLAUDE.md size budget enforced.

Decision-log entry standard format:
- YYYY-MM-DD — <title ≤80c>. <edit-type>: <doc>#<section> [supersedes <prior>].
  Why: <one-sentence>. Commit: <sha>. PR: #N. Related: [[<id>]].

With edit-type vocabulary (spec edit / ADR amendment / new ADR / supersession /
archived / new spec) for machine-parseable categorization by Play 2c toolbox. Lists
what NOT to put in entries (no rationale paragraphs, no restated spec content, no
duplicated info — one decision = one entry).

Strategy spec banner updated to reflect today's second material edit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
jukka-matti added a commit that referenced this pull request May 17, 2026
… latest main) (#199)

* docs: foundational artifacts for docs-strategy-2026 (memo + spec + ADR-083)

Create three foundation docs that the rest of Play 1 rests on:
- 2026-05-16-docs-strategy-memo.md: 1-page CTO memo (§8 of plan)
- 2026-05-16-docs-strategy-design.md: full strategy spec (§§1-7, 10)
- adr-083-eight-purpose-doc-taxonomy.md: ADR for the schema change

ADR-083 captures the 8-purpose × 4-tier two-axis schema, STATUS alias
map (22→4), AUDIENCE alias map (14→3), CATEGORY→topic-tags replacement,
and the migration approach for Play 1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(scripts): collapse frontmatter schema (22→4 STATUS, free-form topic, 3 AUDIENCE) + add purpose/tier + drift fields

Per ADR-083: two-axis schema (8 purposes × 4 tiers) replaces the
over-engineered 22-STATUS × 18-CATEGORY × 14-AUDIENCE triplet.

scripts/docs-frontmatter-schema.mjs:
- Add PURPOSE enum (8 values) and TIER enum (4 values)
- Collapse STATUS from 22 → 4 canonical values
- Export STATUS_ALIAS_MAP (11 old→new mappings) for transitional validation
- Export AUDIENCE_ALIAS_MAP (14 old→new mappings)
- Remove CATEGORY enum; topic tags are now free-form
- Collapse AUDIENCE from 14 → 3 canonical values (human/agent/both)
- Add new optional fields: purpose, tier, last-verified,
  verified-against-commit, supersedes, related
- Update classify() for new folder paths (Play 1 prep)

scripts/check-doc-frontmatter.mjs:
- Warn (not fail) on aliased STATUS/AUDIENCE values
- Hard-fail on unknown PURPOSE/TIER when present
- Add --report mode: counts docs missing purpose + tier

scripts/docs-frontmatter-fix.mjs:
- Apply STATUS_ALIAS_MAP and AUDIENCE_ALIAS_MAP
- Handle inline array audience form (audience: [analyst, engineer])
- Backfill purpose + tier via path heuristics (all 521 docs covered)

Applied to all 521 docs: 0 hard violations, 0 transitional warnings.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(agent-context): add 3 Tier 1 supporting docs (quickstart + package-router + store-state-glossary)

New docs at docs/agent-context/ (TEMP location; will move to docs/living/agent-context/ in Play 1b):
- onboarding-quick-start.md: 5-minute agent orientation covering wedge V1 direction, hard invariants,
  where-to-look table, and common pitfalls (Math.random, hex colors, --no-verify, root-cause language)
- package-router.md: 20-row routing table mapping work areas → primary CLAUDE.md + related CLAUDEs
  + ADRs + rules/invariants + suggested skills
- store-state-glossary.md: full glossary of all 7 stores × 3 layers (Document/Annotation/View) per
  ADR-078 + F4, with top fields, persistence details, and hard rules per store

All 3 docs use the new two-axis schema (purpose, tier, audience, topic, last-verified) introduced in
the docs-strategy-2026 plan. Verified against packages/stores/src/*.ts at commit 5ee58dc.
pnpm docs:check passes (527 docs validated, no issues).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(skills): add 3 Tier 1 agent-context skills (quickstart + package-router + store-state-glossary)

Closes the 4%-of-living agent-context gap identified in plan §7.1. Three skills for fresh subagent
dispatch orientation (Play 3 Tier 1):

- agent-context-quickstart: loads docs/agent-context/onboarding-quick-start.md; description triggers
  on any "start of session", "new subagent", or "need context" phrasing; covers wedge V1 direction,
  hard invariants, where-to-look, and common pitfalls
- package-router: routes work areas (canvas, stats, charts, stores, i18n, azure, pwa, ui, hooks,
  coscout, response-paths, capability/yamazumi/defect/performance/process-flow modes, projects tab,
  investigation wall, evidence map, sample data) to primary CLAUDE.md + related CLAUDEs + ADRs +
  rules; description triggers on "which package", "where to look", "which CLAUDE.md"
- store-state-glossary: covers all 7 stores × 3 layers per ADR-078 + F4; description triggers on
  "which store", "what state lives", "store state" phrasing; links to full doc and packages/stores/CLAUDE.md

All 3 skills follow the SKILL.md spec (name ≤64 chars, description with what+when, body ≤200 lines).
Skills use force-add to override .claude/.gitignore — standard pattern for project-scoped skills.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(.claude): rename .claude/rules/ → .claude/invariants/ + update path references

Renames 6 constraint files (stats, testing, charts, coscout-prompts, i18n,
azure-storage) from .claude/rules/ to .claude/invariants/ to clarify their
purpose as policy-level invariants (not procedure routers). Updates all
active references in CLAUDE.md, package-router.md, and two implementation
docs to the new path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(.claude): add INVARIANTS.md synthesis index

Creates .claude/INVARIANTS.md as the single entry-point for all
VariScout cross-cutting non-negotiables. Organises invariants into
three tiers — hard (lint/test-enforced), soft (convention + reviewer),
and topic-scoped (load on demand) — with canonical home and enforcement
mechanism cited for each. Identifies two open enforcement gaps (Math.random
and Tailwind @source) for follow-up in investigations.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs: replace prose invariant duplication with [[invariant]] links + log enforcement gaps

Links root CLAUDE.md §Invariants and onboarding-quick-start.md §Hard
Invariants to the new .claude/INVARIANTS.md index instead of restating
the full invariant list. Updates agent-context-quickstart skill to
explicitly load INVARIANTS.md in its How to Use procedure. Logs two
open enforcement gaps (Math.random ban, Tailwind @source check) to
docs/investigations.md as candidates for Play 7.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(scripts): add docs:gen-arch — auto-generate dependency/exports/Tailwind architecture doc

Adds scripts/docs/gen-arch.mjs that walks package.json files (dep graph),
tsconfig.json paths (sub-path export map), and apps/*/src/index.css (@source
directives) to emit docs/05-technical/architecture-generated.md.

Wired as pnpm docs:gen-arch in root package.json. Pre-push hook regenerates
and fails if checked-in version is stale, surfacing drift immediately.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* docs(system): add initial auto-generated architecture doc + cross-link from technical index

Adds docs/05-technical/architecture-generated.md (initial committed version).
Updates docs/05-technical/index.md to add inbound link so the doc is not
an orphan (required by pnpm docs:check orphan check).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* docs(design): add canonical CoScout AX-design doc consolidating ADR-060/068/069 + prompt rule

Creates docs/01-vision/coscout-ax-design.md as the single canonical AX-design
surface for CoScout: persona, voice, tier-gated behaviors (table), five-pillar
knowledge architecture, three-boundary safety, prompt engineering link,
tool-calling, voice input, eval discipline, mode-aware methodology coaching,
and related artifacts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* docs: cross-link constituent CoScout ADRs + invariant + router to canonical AX-design

- ADR-060, ADR-068, ADR-069: add related: [coscout-ax-design] to frontmatter
  + brief "See canonical AX design" note near each ADR title
- .claude/invariants/coscout-prompts.md: add related: [coscout-ax-design]
  + see-also note at bottom
- docs/agent-context/package-router.md: update CoScout row to point at
  coscout-ax-design.md as canonical entry point (was packages/core/CLAUDE.md)
- .claude/INVARIANTS.md: update CoScout-prompts topic-scoped row to reference
  coscout-ax-design.md as the first-load for CoScout work

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore(prettier): exclude auto-generated arch doc + regenerate

The Play 7 gen-arch script outputs compact markdown tables; lint-staged
prettier reformatted them on commit, causing the pre-push staleness check
(`git diff --exit-code` after regeneration) to fire on every push.

Fix: add `.prettierignore` excluding the generated file so committed
content matches the script's output verbatim.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(strategy): revise Play 2b to SSoT-by-doc-type discipline + ship convention doc

Discipline gap surfaced by the 2026-05-17 wedge-amendment incident: a mid-flight
design change to wedge spec was captured as `2026-05-16-improve-tab-amendment-design.md`
(orphan side spec), invisible to a fresh session reading only the canonical wedge spec.
Convention alone didn't prevent it; mechanical enforcement does.

Strategy spec (edited in place, dogfooding the principle):
- §1 Context: note the discipline-drift failure mode + why mechanical enforcement matters
- §2.6 per-purpose table: design row → edit-in-place; remember row → append-only
- §2.7 NEW: Doc Discipline (SSoT by doc type). Design specs edit-in-place; ADRs
  amendment-block-at-bottom; decision-log append-only; generated never-hand-edit;
  plan files ephemeral. Anti-pattern table + spec lifecycle states + edit-in-place
  mechanics + "decision-log as temporal index" framing.
- Play 2b: revised from "addendum threads on all living docs" (wrong-shape — conflated
  design specs with ADRs) → "SSoT discipline by doc type" with validator forbidding
  `*-amendment-*.md` / `*-revision-*.md` / `*-update-*.md` filenames + lifecycle-state
  enforcement. Marked safe-parallel — ships now, no Play 1b dependency.
- §4 migration: shipped/deferred status table reflecting current execution state
- §10 risks: 3 new rows (discipline drift, validator false-positives, body staleness)

Memo: aligned §What we're changing + §plays item 2 + §What we kill; added `last-verified`.

NEW canonical: `docs/agent-context/doc-discipline.md` — focused reference (~150 lines)
loaded by `agent-context-quickstart` skill on session start. Includes:
- Doc-types + update-patterns table (7 types)
- Anti-patterns table with right-pattern column
- Spec lifecycle states (draft → active → delivered → superseded → archived)
- Edit-in-place mechanics for design specs (5-step procedure)
- Decision tree: "I need to change a canonical doc → which pattern?"
- Origin story citing the wedge-amendment incident

agent-context-quickstart SKILL.md: wires doc-discipline.md as step 4 ("If your task
involves editing ANY canonical doc"). Added to Supporting Documents list.

This commit dogfoods the principle: strategy spec edited in place, not as an
`*-amendment-design.md` side file. Plan file at ~/.claude/plans/ updated separately
with a banner pointing to the canonical spec as the SoT going forward.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore: regenerate arch doc

Routine regen after staleness check (per Play 7 pre-push convention).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(discipline): add reader-first status banner principle (top of file)

Question: should amendment/relevance info be at the top of files? Does
wikilink structure preserve that?

Answer: YES, top. Frontmatter is for tooling; banner is for readers
(humans + agents). Wikilinks preserve graph structure but are passive at
read time — banners are active. Industry convention (MDN, Stripe, IETF,
Wikipedia, Tailscale): status at top, amendments at bottom (ADRs only).

Added to doc-discipline.md §Reader-first banners:
- Required/recommended matrix per condition (status: superseded, supersedes:,
  recent material edit, delivered, ADR with amendments)
- 6 concrete banner templates (superseded, recent edit, active build,
  delivered, ADR amended, archived)
- Origin story citing wedge-amendment incident
- "Wikilinks don't substitute for banners" explanation
- Banner + frontmatter both required (machine vs reader)
- Play 2b validator extensions for banner enforcement (4 new rules)

Added to strategy spec §2.7:
- New subsection "Reader-first banners at the top" pointing to discipline doc
- Edit-in-place mechanics step 3 now includes "add status banner"
- Play 2b validator scope extended in mechanics section

Dogfooded: strategy spec itself now carries a banner at top noting active
build via PR #184 + last material edit 2026-05-17.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(discipline): elevate 4 affirmative principles + codify decision-log format + classify agent manifests

Audit gaps surfaced after yesterday's discipline shipment:
1. "One canonical home per concept" was buried as an anti-pattern; now stated affirmatively as Principle #2
2. Decision-log entry format was informal; now codified with edit-type vocabulary for Play 2c toolbox parsing
3. CLAUDE.md/AGENTS.md/llms.txt weren't classified in the doc-types table

Both strategy spec §2.7 and doc-discipline.md updated in parallel:

Core principles (in priority order):
1. Doc-type discipline
2. One canonical home per concept (Play 4 enforces)
3. Reader-first banners
4. Decision-log as temporal index

Wedge-amendment incident reframed as a simultaneous violation of principles 1+2+3,
making clear why all four need mechanical enforcement (Play 2b).

Doc types extended in the at-a-glance list: investigations + memory + agent manifests
added (was 5 types covered, now 8). Agent manifests get an explicit row in the
doc-discipline.md table noting they're the "first read" surface every agent dispatch
loads — keep tight, CLAUDE.md size budget enforced.

Decision-log entry standard format:
- YYYY-MM-DD — <title ≤80c>. <edit-type>: <doc>#<section> [supersedes <prior>].
  Why: <one-sentence>. Commit: <sha>. PR: #N. Related: [[<id>]].

With edit-type vocabulary (spec edit / ADR amendment / new ADR / supersession /
archived / new spec) for machine-parseable categorization by Play 2c toolbox. Lists
what NOT to put in entries (no rationale paragraphs, no restated spec content, no
duplicated info — one decision = one entry).

Strategy spec banner updated to reflect today's second material edit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(agent-context): align with current main reality — 7-tab nav, €120, 3 personas, Math.random ESLint enforced

Stale-reference fix pass after cherry-picking PR #184's infrastructure onto fresh
branch off latest main. Aligns agent-context surface with what shipped today:

- `docs/agent-context/onboarding-quick-start.md`:
  - €99 → €120; 6-tab → 7-tab nav
  - "Improve = stage inside Projects" → "Improve = top-level verb tab" (per 2026-05-16
    Improve-tab amendment); Project stages collapsed to Charter→Approach→Sustainment
  - Add 3 personas inside Project: Lead (full edit + manages membership) / Member
    (full edit) / Sponsor (Report-only at V1, signoff out-of-band). Every subagent
    loading quickstart sees all 3 on first read.
  - Tier-gating "fully retired" (no more isPaidTier() checks)
  - VariScout Process named-future now points to `docs/01-vision/variscout-process/`

- `.claude/skills/agent-context-quickstart/SKILL.md`: same updates (Key Facts section)

- `docs/agent-context/package-router.md`: Projects-tab row updated — "Lead/Member/Sponsor
  roles" → "3 personas: Lead/Member/Sponsor"; stage list shortened; Improve as top-level
  noted; €120 pricing

- Root `CLAUDE.md`: add "3 personas within each Project (Lead/Member/Sponsor)" to the
  strategic-direction line (the rest was already current — €120, 7-tab, Improve restored)

- `.claude/INVARIANTS.md` §Enforcement Gaps: Math.random ban marked RESOLVED 2026-05-17
  via PR #198 (Tier 1 Math.random retirement + ESLint guard shipped)

Per user's terminology decision (2026-05-17): use "3 personas" framing consistently in
agent-context docs (simpler than wedge spec's "1 persona + 3 ACL roles"). Specialist
is the ICP description, not a 4th persona. Open question logged for follow-up:
unify wedge spec terminology to match (out of scope for this PR).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(transcripts): promote docs-strategy-2026 brainstorm plan file to repo transcript

Per the doc-discipline.md ephemeral-promotion rule: plan files in ~/.claude/plans/
are session-private by default; SELECTIVE promotion to docs/ephemeral/transcripts/
for LANDMARK sessions. The docs-strategy-2026 brainstorm qualifies — it produced
the foundational strategy + ADR-083 + the SSoT-by-doc-type discipline.

What this preserves in repo:
- Full design journey (8 purposes × 4 tiers, audit findings from Agent 1 + Agent 2)
- Mid-session pivots (wedge-conflict surfaced → split Play 1 into 1a safe + 1b
  deferred; original "addendum threads" Play 2b revised to SSoT discipline after
  the wedge-amendment incident)
- §11 post-PR-184 recalibration (cherry-pick recovery plan + Play 1b/2a reorder +
  3-personas terminology decision)

Frontmatter added: purpose: remember, tier: ephemeral, status: archived,
audience: human, topic: [docs-strategy, transcript, brainstorm].

Top banner converted from "plan-file pointing-at-canonical" to "archived transcript
pointing-at-canonical" — the file IS now the canonical historical record.

Inbound link added from strategy spec (avoids orphan check). Future readers see:
spec for "what" (current intent); transcript for "why each decision was made".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(schema): add 'named-future' to STATUS_ALIAS_MAP

The user's PR #193 (VariScout Process named-future capture) created 8 docs at
`docs/01-vision/variscout-process/` with `status: 'named-future'`. That value
was valid in the old 22-value STATUS enum but missing from my collapsed
4-value canonical set.

Maps to 'active' since named-future docs ARE actively maintained design
artifacts for the future product — not draft (designed) or superseded
(replaced). They describe what the named-future product WILL be.

Resolves 8 hard-fail check-doc-frontmatter errors blocking push.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(schema): named-future earns its own STATUS value (5 canonical, not 4)

User feedback: aliasing 'named-future' to 'active' (commit 3a6928b) overstated
the commitment level. VariScout Process docs at docs/01-vision/variscout-process/
are aspirational — contingent on V1 reaching 500+ customers. They're not in
active design; they describe what's COMMITTED for a future product line.

The 4-value collapse (draft/active/superseded/archived) was overzealous. The
22→4 reduction missed a meaningful distinct lifecycle state. Promoting
'named-future' to a canonical 5th status preserves the semantic intent:

- draft: designing; not yet building
- active: designed; build underway
- **named-future: aspirational/conditional commitment** (not in active design)
- superseded: replaced by another spec
- archived: historical reference only

Changes:
- scripts/docs-frontmatter-schema.mjs: add 'named-future' to STATUS enum;
  remove from STATUS_ALIAS_MAP (no longer aliased)
- docs/agent-context/doc-discipline.md: spec-lifecycle table extended; example
  cites VariScout Process docs; added note on 'delivered' being a soft state
  signalled by `delivered-by:` frontmatter (not a status: enum value)
- docs/superpowers/specs/2026-05-16-docs-strategy-design.md: schema section +
  collapse summary + migration sequence updated (22→5 not 22→4)
- docs/superpowers/specs/2026-05-16-docs-strategy-memo.md: same

Resolves 8 hard-fail check-doc-frontmatter errors for variscout-process/ docs
WITHOUT semantically mis-labeling them.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore: regenerate arch doc

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file github_actions Pull requests that update GitHub Actions code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant