Skip to content

chore(ci): bump actions/checkout from 4 to 6#71

Closed
dependabot[bot] wants to merge 211 commits into
mainfrom
dependabot/github_actions/actions/checkout-6
Closed

chore(ci): bump actions/checkout from 4 to 6#71
dependabot[bot] wants to merge 211 commits into
mainfrom
dependabot/github_actions/actions/checkout-6

Conversation

@dependabot

@dependabot dependabot Bot commented on behalf of github May 12, 2026

Copy link
Copy Markdown
Contributor

Bumps actions/checkout from 4 to 6.

Release notes

Sourced from actions/checkout's releases.

v6.0.0

What's Changed

Full Changelog: actions/checkout@v5.0.0...v6.0.0

v6-beta

What's Changed

Updated persist-credentials to store the credentials under $RUNNER_TEMP instead of directly in the local git config.

This requires a minimum Actions Runner version of v2.329.0 to access the persisted credentials for Docker container action scenarios.

v5.0.1

What's Changed

Full Changelog: actions/checkout@v5...v5.0.1

v5.0.0

What's Changed

⚠️ Minimum Compatible Runner Version

v2.327.1
Release Notes

Make sure your runner is updated to this version or newer to use this release.

Full Changelog: actions/checkout@v4...v5.0.0

v4.3.1

What's Changed

Full Changelog: actions/checkout@v4...v4.3.1

v4.3.0

What's Changed

... (truncated)

Changelog

Sourced from actions/checkout's changelog.

Changelog

v6.0.2

v6.0.1

v6.0.0

v5.0.1

v5.0.0

v4.3.1

v4.3.0

v4.2.2

v4.2.1

v4.2.0

v4.1.7

v4.1.6

... (truncated)

Commits

leagames0221-sys and others added 30 commits April 22, 2026 16:13
- Root configs: package.json, pnpm-workspace.yaml, turbo.json
- Env: .env.example with per-app DB URLs + app/migrator role separation
- Infra: docker-compose (pgvector/pg16 + redis:7-alpine) + multi-db init script
- Git hygiene: .gitignore, .gitattributes (LF normalization), .nvmrc (Node 20)
- License: MIT
- Docs: 13-part design bible in docs/design/ covering Boardly + Knowlex
  - Overview, monorepo structure, requirements, ER schemas (Prisma)
  - OpenAPI specs, Week 3 daily task breakdown
  - ADR 0001-0022, STRIDE threat model, Runbook, rate limits, retention
  - RAG prompt registry + golden QA eval pipeline
  - Interview Q&A 30 + portfolio LP + demo storyboards
  - Self-review critical/high fix log
apps/
- collab (Boardly): Next.js 16 + Turbopack + TailwindCSS + TS, port 3000
- knowledge (Knowlex): Next.js 16 + Turbopack + TailwindCSS + TS, port 3001

packages/
- @craftstack/ui: shared React components entry
- @craftstack/auth: Auth.js v5 wrapper entry
- @craftstack/db: Prisma client + withTenant helper entry
- @craftstack/logger: pino + Sentry entry
- @craftstack/config: shared tsconfig.base.json + prettier.config.js
- @craftstack/api-client: OpenAPI-generated types entry

Workspace install verified (pnpm 9.15, Node 20, 355 packages).
Collab production build passes.
Shared packages (ui/auth/db/logger/api-client) had lint/typecheck scripts
pointing to tools that were not installed (eslint/tsc configs missing).
Turbo invoked them and failed with exit code 2.

Scripts will be re-added per package when actual source + configs land.
Apps (collab/knowledge) retain their Next.js-provided lint/typecheck.
- prisma + @prisma/client 7.7.0, dotenv, tsx dev deps
- prisma.config.ts: Prisma 7 native config (migrator URL resolution)
- .gitignore: /src/generated/prisma
- dotenv/config imported for env var loading
- pg_trgm extension declared for future full-text search
…ership, Invitation)

Schema follows docs/design/05_prisma_schemas.md:

Auth.js v5 adapter tables:
  - Account (provider+providerAccountId unique)
  - Session (sessionToken unique)
  - VerificationToken (identifier+token unique)

Core domain (Boardly):
  - User: email-unique identity + locale/theme preferences
  - Workspace: slug-unique tenant with owner + soft-delete
  - Membership: user x workspace with Role enum (OWNER/ADMIN/EDITOR/VIEWER)
  - Invitation: email invites with tokenHash + expiresAt + optional inviter (SetNull)

Design decisions applied:
  - onDelete cascades follow docs/design/12_critical_fixes.md C-1
  - Invitation.inviterId nullable + SetNull so invites survive user deletion
  - Indexes: email, slug, owner, deletedAt, workspace+role, workspace+email

Generator: Prisma Client 7.7 with fullTextSearchPostgres + postgresqlExtensions.
prisma format and prisma generate both pass.
…ity log

Schema additions (docs/design/05_prisma_schemas.md):

Enums:
  - ActivityAction (24 variants) for AuditLog-style append-only tracking
  - NotificationType (MENTION/ASSIGNED/DUE_SOON/INVITED/COMMENT_ON_CARD)

Kanban domain:
  - Board: workspace-scoped with color/icon/archived/position, soft delete
  - List: LexoRank position, optional WIP limit
  - Card: optimistic locking via version column (ADR-0007),
          title/description/dueDate/position, Cascade from List

Labels (many-to-many via CardLabel):
  - Label: workspace-scoped name+color, unique per workspace
  - CardLabel: composite PK (cardId, labelId)
  - CardAssignee: composite PK (cardId, userId) with assignedAt

Comments & attachments:
  - Comment: self-referential parentId for threads, soft delete
  - Mention: (commentId, userId) unique for per-user notification dispatch
  - Attachment: R2-backed (r2Key unique), uploader reference, MIME metadata

Observability:
  - ActivityLog: workspace-scoped audit trail with JSON payload,
                 actor SetNull on user delete (ADR-0010 C-1)
  - Notification + NotificationSubscription: Web Push VAPID endpoints

prisma format/validate/generate all pass.
Full monorepo lint/typecheck/build verified locally.
src/lib/db.ts exports a global-cached PrismaClient so HMR in Next.js
does not spawn a new connection pool on every module reload.

- dev: log query/error/warn
- prod: log error only (avoid PII leakage, ADR-0009 observability plan)
- globalThis-based caching gated on NODE_ENV !== production
src/lib/lexorank.ts wraps the `lexorank` npm package (Jira-compatible)
per ADR-0006 + ADR-0021.

API:
  - first(): rank placed before everything
  - last():  rank placed after everything
  - between(prev?, next?): insert between two neighbors
  - compare(a, b): stable comparator for Array.sort

Tests (src/lib/lexorank.test.ts, all passing):
  1. first() < last()
  2. between(first, last) strictly between
  3. between(null, null) yields a valid rank
  4. between(prev, undefined) places after prev
  5. between(undefined, next) places before next
  6. repeated insertions remain strictly ordered
  7. compare is antisymmetric

vitest.config.ts: node env, v8 coverage over src/lib/.
…r-pg)

Prisma 7 constructor requires either an `adapter` or `accelerateUrl`;
plain DATABASE_URL no longer auto-configures the client.

- @prisma/adapter-pg + pg + @types/pg added
- src/lib/db.ts instantiates PrismaClient({ adapter, log })
- same HMR-safe globalThis caching preserved
- production can later swap the adapter for Neon HTTP driver without
  touching call sites

Also: .gitignore the harness-local .claude/ so it does not pollute the repo.
Auth.js v5 (next-auth@5.0.0-beta.31) + @auth/prisma-adapter setup per
ADR-0003 (database session strategy for server-side revocation).

src/auth/
  - config.ts   : NextAuthConfig with PrismaAdapter + Google/GitHub
                  providers + signin page override, session callback
                  exposes internal user.id
  - index.ts    : re-exports { handlers, signIn, signOut, auth }
  - handlers.ts : thin shim for the app route handler
  - rbac.ts     : roleAtLeast / hasRole / requireRole (throws RoleError)
  - rbac.test.ts: exhaustive 4x4 hierarchy matrix (16 Vitest cases)
  - types.d.ts  : augment Session with internal user.id

vitest.config.ts updated to resolve @/ path alias and widen coverage
to src/**/*.ts (excluding app/, generated/, and *.test.ts).
…guard

src/app/api/auth/[...nextauth]/route.ts
  - Re-exports GET/POST from the Auth.js handlers

src/app/signin/page.tsx
  - Server component with async action handlers for Google/GitHub signIn
  - Inline SVG brand icons (no extra dependency)
  - Redirects to /dashboard (or callbackUrl) if already authenticated
  - Dark neutral-950 aesthetic matching the Boardly brand

src/proxy.ts
  - Next.js 16 renamed `middleware` to `proxy`
  - Default-export auth() so the proxy runtime recognizes the function
  - Matcher excludes /signin, /api/auth, and Next static assets

Verified with preview: /signin renders 200, /dashboard redirects 307
through the proxy to /signin as expected (no dashboard route yet).
- ApiError base class with status/code/message/details
- UnauthorizedError (401), ForbiddenError (403), NotFoundError (404),
  ConflictError (409), BadRequestError (400)
- Shape matches OpenAPI Error schema (docs/design/06_openapi_specs.md)
- handle(): Route Handler wrapper that turns thrown ApiErrors into
  JSON 4xx responses and unexpected errors into logged 500s
Returns every non-deleted workspace the authenticated user belongs to,
ordered by join date desc. Unauthenticated requests get a 401 JSON
payload (handled by the new errors/handle wrapper).

src/server/workspace.ts
  - listWorkspacesForUser(userId): joins Membership + Workspace,
    filters out soft-deleted workspaces, returns { id, name, slug,
    color, iconUrl, role }

src/app/api/workspaces/route.ts
  - GET handler wired through handle() so errors become proper JSON
  - auth() checked first; throws UnauthorizedError if missing session
src/app/page.tsx
  - Root '/' now acts as a session gate: authenticated -> /dashboard,
    unauthenticated -> /signin. Removes the scaffold landing content.

src/app/dashboard/page.tsx
  - Server component rendering header with user email + sign-out form
  - Workspace grid (1/2/3 columns responsive) with color swatch,
    name, /slug path, and role badge (OWNER/ADMIN/EDITOR/VIEWER)
  - Empty-state CTA when the user has no memberships
  - 'New workspace' button placeholder pointing at /workspaces/new

src/proxy.ts
  - Matcher now excludes /api/* so API routes handle their own auth
    and return 401 JSON instead of 307 redirects to /signin.
    Confirmed: GET /api/workspaces without session returns
    { code: 'UNAUTHORIZED', message: 'Authentication required' }
    with HTTP 401. Page routes still redirect as expected.
Uniform LF, double quotes, trailing commas 'all' applied across
existing source files after wiring up prettier config.
src/lib/validation.ts
  - parseCreateWorkspaceInput(raw): trims, lowercases slug, enforces
    slug regex ^[a-z0-9-]{3,32}$, 80-char name cap, #RRGGBB color
  - Aggregates every field error into BadRequestError.details.fieldErrors
    so the client can highlight individual fields

src/lib/validation.test.ts
  - 8 cases: valid body, valid color, non-object body, bad slug,
    missing name, overlong name, malformed color, slug normalization
src/server/workspace.ts
  - createWorkspace(userId, input): transactional create with owner
    Membership row; throws ConflictError('SLUG_TAKEN') on collision

src/app/api/workspaces/route.ts
  - POST handler: auth check, body parse, create, 201 with the row
  - Validation errors surface as 400 fieldErrors; slug conflict as 409

src/app/workspaces/new/page.tsx
  - Server component form with Tailwind dark-mode styling
  - Async server action that catches ApiError, rehydrates field values
    via query string, and re-renders with the error banner
  - Native HTML pattern='[a-z0-9-]{3,32}' mirrors server-side regex

Verified: POST /api/workspaces unauthenticated returns 401 JSON;
/workspaces/new unauthenticated redirects to /signin with callbackUrl.
apps/collab/next.config.ts
  - X-Content-Type-Options: nosniff
  - X-Frame-Options: DENY
  - Referrer-Policy: strict-origin-when-cross-origin
  - Permissions-Policy: camera/microphone/geolocation/payment denied
  - Strict-Transport-Security: 2 years + includeSubDomains + preload
  - poweredByHeader: false
  - reactStrictMode: true
  - CSP intentionally deferred until external origins are finalized

docs/architecture/system-overview.md
  - Mermaid graph of Edge, Vercel, Fly.io, Data, External APIs,
    Observability layers with all relationships drawn
  - Per-app resource isolation table
  - Two concrete request paths (card edit, RAG question) walking
    through the full round trip
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v4...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [pnpm/action-setup](https://github.com/pnpm/action-setup) from 4 to 6.
- [Release notes](https://github.com/pnpm/action-setup/releases)
- [Commits](pnpm/action-setup@v4...v6)

---
updated-dependencies:
- dependency-name: pnpm/action-setup
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4 to 6.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](actions/setup-node@v4...v6)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps the react group with 2 updates: [react](https://github.com/facebook/react/tree/HEAD/packages/react) and [react-dom](https://github.com/facebook/react/tree/HEAD/packages/react-dom).


Updates `react` from 19.2.4 to 19.2.5
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.2.5/packages/react)

Updates `react-dom` from 19.2.4 to 19.2.5
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.2.5/packages/react-dom)

---
updated-dependencies:
- dependency-name: react
  dependency-version: 19.2.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: react
- dependency-name: react-dom
  dependency-version: 19.2.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: react
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
/api/health
  - Cheap liveness check (no DB hit) for UptimeRobot 4-minute pings
  - Keeps the Neon free tier warm (ADR-0016)
  - Cache-Control: no-store so the poll always reaches the app

not-found.tsx
  - Branded 404 with Back to dashboard CTA

error.tsx
  - Global error boundary (client component)
  - Shows error.digest for Sentry correlation once wired
  - Try again + Go home buttons
  - Uses next/link per no-html-link-for-pages lint rule
Same X-Content-Type-Options / X-Frame-Options / Referrer-Policy /
Permissions-Policy / HSTS plus poweredByHeader=false, reactStrictMode=true.
prisma/seed.ts
  - Uses the Prisma PG driver adapter + DIRECT_DATABASE_URL (migrator)
  - Upserts 2 users, 1 workspace with 2 memberships + 3 labels
  - Creates a Welcome board with 3 LexoRank-ordered lists and 3 cards
  - Idempotent via upsert + skipDuplicates for rerun safety

pnpm --filter collab db:seed once Docker/Neon is reachable.
src/server/workspace-detail.ts
  - loadWorkspaceForMember(userId, slug): returns null for non-members
    so the caller can 404 without leaking existence
  - One round trip via nested include: boards + memberships + user
  - Skips soft-deleted workspaces and boards

src/app/w/[slug]/page.tsx
  - Header with workspace color swatch + slug crumb + back link
  - Boards grid with 'New board' CTA gated by role (OWNER/ADMIN/EDITOR)
  - Empty state when no boards exist
  - Members list with role badges and avatar initials
  - Self role displayed inline next to member count
  - Consistent RoleBadge component (also used in dashboard)
src/server/board.ts
  - createBoard: enforces role >= EDITOR via roleAtLeast() before INSERT
  - New boards are placed at the bottom of the workspace via LexoRank last()
  - Throws NotFoundError if workspace missing, ForbiddenError otherwise

src/app/w/[slug]/boards/new/page.tsx
  - Server-action form with Tailwind dark styling
  - Rehydrates prior values + error banner via query string
  - Redirects to /w/[slug]/b/[boardId] on success

src/app/w/[slug]/b/[boardId]/page.tsx
  - Workspace-scoped board query: 404 for non-members or missing board
  - Static kanban layout (lists + cards); realtime editing arrives in Week 6
  - Per-list card count with optional WIP limit display
  - Subtle board-color tint on the header gradient
leagames0221-sys and others added 16 commits May 16, 2026 19:01
…des (fast-uri, hono) (#75)

Resolves pnpm audit failures on main (2/2 FAIL → expected GREEN after merge).

## Vulnerabilities closed (audit literal verify)

Before: 22 vulns (3 low + 10 moderate + 9 high)
After:   2 vulns (0 low +  2 moderate + 0 high) → `pnpm audit --audit-level=high` exit 0

### High severity (7) — all in next.js 16.2.4
- GHSA-8h8q-6873-q5fj: DoS via Server Components (patch ≥16.2.5)
- GHSA-26hh-7cqf-hhc6: Middleware/Proxy bypass via segment-prefetch (patch ≥16.2.6)
- GHSA-mg66-mrh9-m8jx: DoS via connection exhaustion in Cache Components (patch ≥16.2.5)
- GHSA-c4j6-fc7j-m34r: SSRF via WebSocket upgrades (patch ≥16.2.5)
- GHSA-492v-c6pp-mqqv: Middleware/Proxy bypass via dynamic route param injection (patch ≥16.2.5)
- GHSA-267c-6grr-h53f: Middleware/Proxy bypass in App Router segment-prefetch (patch ≥16.2.5)
- GHSA-36qx-fr4f-26g5: Middleware/Proxy bypass in Pages Router using i18n (patch ≥16.2.5)

→ Bump next from 16.2.4 → 16.2.6 in apps/collab + apps/knowledge package.json (covers all 7)

### Transitive deps (fast-uri, hono) — pnpm overrides
- fast-uri: high × 2 path-traversal + host-confusion (patch ≥3.1.2)
- hono: 3 vulns in Prisma dev tooling (patch ≥4.12.18)

→ Add to root package.json `pnpm.overrides` (transitive deps, can't update via direct dep)

## Local verify PASSED (D-WRANGLER-LOCAL-FIRST 一般化、 pre-push verification)

- `pnpm install` → lock regenerated, 0 errors
- `pnpm lint` → 0 errors (4 pre-existing warnings unrelated to this change)
- `pnpm typecheck` → 0 errors
- `pnpm test` → 174 / 174 PASS (26 test files)
- `pnpm audit --audit-level=high` → exit 0

## Remaining moderate (2)
Will be tracked separately; not blocking CI (pnpm-audit gate is `--audit-level=high`).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: leagames0221-sys <leagames0221@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(design): sanitize cross-project references

* docs(adr): generalize domain term reference in ADR-0063
…tion) (#82)

* feat(data-analytics-demo): Phase 0 scaffold + ADR-0070 (polyglot adoption)

T-01 + T-02 of the Spec-Driven Stage 4 task plan for the data-analytics-demo
package. Adds the polyglot scaffold (Python sub-package + pnpm workspace
member) plus ADR-0070 documenting the design intent.

Scaffold (T-01):
- packages/data-analytics-demo/{pyproject.toml,package.json,Makefile}
- src/data_analytics_demo/{__init__.py,cli.py} (CLI stub via typer)
- README.md with 5-cmd quickstart + zero-credit-card constraint
- .gitignore for warehouse/ + ml/artifacts/ + dashboard/build/
- DuckDB pinned >= 1.4.2 (CVE-2025-64429 mitigation)

ADR (T-02):
- docs/adr/0070-data-analytics-demo-polyglot-adoption.md
- 6 tradeoffs + 6 stack inheritance + 1 rejected (jaffle-shop-template)
- 5 new load-bearing entries in docs/adr/_claims.json
- check-adr-claims.mjs: 77/77 PASS

.env.example creation is deferred to T-03 when the first env var becomes
load-bearing (no functional gap in Phase 0).

Boundary: only files inside packages/data-analytics-demo/ + new ADR file +
_claims.json edit. No Forbidden surface touched. Verified 0 leaks of
cross-project vocabulary (D-HIVE-OPACITY).

* fix(data-analytics-demo): unblock CI — turbo no-op for Python pkg + ADR count bump

Two follow-up fixes to PR #82 surfacing from CI:

1. `lint / typecheck / test / build` (turbo lint failure)
   Removed `lint` + `test` scripts from packages/data-analytics-demo/package.json.
   `make lint` / `make test` (ruff + mypy + pytest) require the Python toolchain,
   which the existing TS-focused CI does not provision. Turbo silently skips
   tasks a workspace member does not declare, so the polyglot package now
   coexists cleanly. The Python lint/test path lands in T-12 via a dedicated
   python-test.yml workflow.

2. `doc drift detect` (ADR count claim drift)
   ADR-0070 brought the resolvable ADR count from 67 to 68. Updated:
   - README.md (× 3): prose claim, file-tree comment, status table
   - docs/hiring/portfolio-lp.md (× 3): prose claims
   - apps/collab/src/app/page.tsx (× 1): Stat label
   Note: apps/knowledge/src/lib/attestation-data.json is gitignored
   (auto-regenerated in CI), so the count there self-heals.

Local verify:
- node scripts/check-doc-drift.mjs    → 0 failure(s), 0 warning(s)
- node scripts/check-adr-claims.mjs   → 77/77 PASS

---------

Co-authored-by: leagames0221-sys <leagames0221@users.noreply.github.com>
* feat(data-analytics-demo): T-03 data generation + T-12 Python CI infra

Phase 1 of the data-analytics-demo bolt-on. Ships the synthetic data
generator (T-03) alongside the Python CI infrastructure (T-12) so the new
Python code is verified by CI from the first commit.

T-03 — Data generation (AC-1.1 to 1.5 + AC-γ.1 + AC-δ.2):
- src/data_analytics_demo/data/schemas.py — Pydantic models for the 4 SaaS
  tables (Customer / Subscription / Event / Invoice)
- src/data_analytics_demo/data/generate.py — Faker + numpy synthesis,
  deterministic via DEMO_RANDOM_SEED (default 42). Writes a DuckDB file at
  warehouse/analytics.duckdb. Engineered signal: trailing-30d event drop-off
  biases churn probability; free-tier customers using premium-feature events
  bias upsell probability (both observable through SQL, no leak from the
  generator into the ML feature surface).
- tests/test_data_generate.py — 7 pytest cases covering each AC.
- Makefile + cli.py — `make data` and `data-analytics-demo data` now do real
  work instead of exit-1 TODO placeholders.

T-12 — Python CI infrastructure:
- .github/workflows/python-test.yml — Python 3.11, install editable + dev,
  run ruff + mypy --strict + pytest (with the 80% coverage gate set in
  pyproject.toml).
- .github/workflows/python-audit.yml — pip-audit --strict against OSV.
- .github/dependabot.yml — pip ecosystem on /packages/data-analytics-demo,
  grouped by dbt / ml / duckdb / dev for review readability.

Design note: ADR-0070 mentioned the DuckDB tpcds extension as a synthetic-data
source. tpcds is a retail benchmark and does not fit the 4-table SaaS schema
this package commits to. Reverted to pure Faker + numpy synthesis; ADR-0070
will be amended in T-13 polish phase to record the deviation.

Local verify:
- python -m compileall on src/ + tests/ → OK
- node scripts/check-doc-drift.mjs       → 0 failure(s), 0 warning(s)
- node scripts/check-adr-claims.mjs      → 77/77 PASS
- HIVE-token sweep on new files          → 0 hits (D-HIVE-OPACITY)

* fix(data-analytics-demo): ruff lint — 4 errors in generate.py

CI feedback from #83 (python-test workflow). All 4 are clean style/typing nits:

- F401: drop unused `from collections.abc import Sequence` (TYPE_CHECKING
  block); the `Sequence` was never referenced.
- UP017: `timezone.utc` -> `UTC` (Python 3.11+ alias).
- T201: `_emit()` is the deliberate single exception to the print-suppression
  rule for this package — annotated with `noqa: T201` plus a docstring note
  so the exception is auditable in code review.
- E501: split the timestamps list comprehension at 121 cols into 3 lines.

Verify: python -m compileall src/ OK.

* fix(data-analytics-demo): mypy — PEP 561 typed marker + 3rd-party overrides

CI feedback from #83 (mypy step). 3 errors clear:

- Add `src/data_analytics_demo/py.typed` (PEP 561 marker). Resolves the two
  `import-untyped` errors on cli.py importing `data_analytics_demo` and
  `data_analytics_demo.data` — the package now declares inline type info.
- Register the marker in [tool.setuptools.package-data] so it ships in the
  installed wheel.
- Add a [[tool.mypy.overrides]] block for pandas / duckdb / faker / shap /
  xgboost / sklearn — none of these publish type stubs that match the current
  Python 3.11 + pandas 3.x stack. pandas-stubs exists but lags pandas
  releases, so ignore_missing_imports is the pragmatic floor.

* chore: trigger CI re-run on latest HEAD (d87e787)

* fix(data-analytics-demo): mypy src-layout dual-path conflict

CI feedback: `mypy src` walked the file as both `src.data_analytics_demo.…`
and `data_analytics_demo.…` because the package is editable-installed AND
src is on the filesystem path.

- pyproject.toml: add `mypy_path = "src"` so mypy resolves the package
  unambiguously through its installed name.
- python-test.yml + Makefile: invoke mypy as `mypy -p data_analytics_demo`
  (installed-package mode) instead of `mypy src` (filesystem walk). Same
  coverage, no path collision.

* fix(data-analytics-demo): drop EmailStr dependency

CI feedback: pydantic.EmailStr requires the optional `email-validator`
package, which is not in our dependency set. No AC requires email-format
validation; the field stores a Faker company_email() string and downstream
consumers (dbt staging, ML features) read it as a string anyway. Dropping
EmailStr removes the runtime dep without any functional change.

---------

Co-authored-by: leagames0221-sys <leagames0221@users.noreply.github.com>
…#86)

Phase 2 of the data-analytics-demo bolt-on. Ships the dbt layer that
transforms the 4 synthetic SaaS source tables into 4 mart tables ready for
the ML and dashboard layers.

T-04 — dbt scaffold + staging + intermediate (AC-2.5):
- dbt_project.yml + profiles.yml (DuckDB target reads
  ../warehouse/analytics.duckdb)
- models/staging/_sources.yml declares the 4 raw tables
- models/staging/stg_{customers,subscriptions,events,invoices}.sql (views,
  thin pass-through + dtype casting)
- models/intermediate/int_customer_features.sql (one row per customer
  combining latest subscription + lifetime event stats + invoice totals)
- models/intermediate/int_event_aggregates.sql (per-customer × event_type
  rollup powering both churn and upsell marts)

T-05 — marts + schema tests (AC-2.1, AC-2.2, AC-2.3, AC-2.4, AC-2.6):
- marts/rfm_segments.sql (R/F/M quintile scoring + 5-bucket label;
  self-anchored to max(event_at) so it's reproducible per seed)
- marts/churn_features.sql (one row per customer; trailing-30d vs lifetime
  daily-avg ratio is the engineered churn signal label)
- marts/upsell_opportunities.sql (one row per free/pro customer; premium /
  advanced event counts as engineered signal; upgraded label)
- marts/cohort_retention.sql (monthly cohort × months-since-signup grid)
- marts/schema.yml (not_null + unique + accepted_values tests, new dbt
  generic-test argument syntax)

Makefile: `dbt` target now runs `dbt run && dbt test` from dbt_project/
with DBT_PROFILES_DIR=. so the project ships its own profile.

.gitignore: add dbt_project/.user.yml (dbt's per-developer anonymous tracking
UUID; not portfolio-relevant).

Local verify on seeded DuckDB (n_customers=1000):
- dbt parse        → OK (deprecation warnings cleared)
- dbt run          → 10/10 OK (4 staging views + 2 int views + 4 mart tables)
- dbt test         → 20/20 PASS (not_null + unique + accepted_values)
- Mart rowcounts   → rfm 1000, churn 1000, upsell 898, cohort 319
- Sanity numbers   → churn rate 26.2% (matches synth ~25% canceled), upsell
                      rate 35.5%, RFM segments distributed across 5 buckets
- Python verify    → ruff OK / mypy OK / pytest 8 PASS (cov 83.92%)
- doc-drift + adr-claims → 0 failure / 77/77 PASS

Co-authored-by: leagames0221-sys <leagames0221@users.noreply.github.com>
Phase 3 of the data-analytics-demo bolt-on. Trains two propensity models
on the dbt marts shipped in #86 and saves the resulting model artifacts +
SHAP summary that the narrative layer (T-08) consumes next.

T-06 — Churn pipeline (AC-3.1〜3.5):
- ml/churn.py — fits a LogisticRegression baseline AND an XGBoost
  classifier on `churn_features`, picks the higher hold-out ROC-AUC, and
  saves model.pkl + metadata.json + shap_summary.json.
- ml/explain.py — SHAP wrapper used by both the churn and (later)
  narrative paths. TreeExplainer first, falls back to model-agnostic.
- ml/_io.py — shared mart loader, fails with clear errors when the
  warehouse / mart is missing (AC-3.4).

T-07 — Upsell propensity (AC-3.6〜3.7):
- ml/upsell.py — fits a LogisticRegression propensity model on
  `upsell_opportunities`, measures hold-out ROC-AUC and lift @ top-10%,
  raises if the lift falls below the 1.5× floor.

Data-generator amendment: the churn signal in `data/generate.py` was
under-engineered (best ROC-AUC was 0.6972, just below the AC-3.2 0.70
floor). Reworked the event generator so churned customers (a) get 4×
lower event weight and (b) have their timestamps biased into the older
half of the history window. The mart's `recent_to_lifetime_ratio` feature
now correlates cleanly with the cancel label, pushing churn ROC-AUC to
0.7448 on a seed=42 / n_customers=1000 run.

Local verify (Python 3.12 venv, deterministic seed=42):
- `make data` + `make dbt` + `make ml` end-to-end OK
- Churn ROC-AUC = 0.7448 (LR wins; XGBoost 0.7196), AC-3.2 PASS
- Upsell lift @ top-10% = 2.81× (vs 1.5× floor), AC-3.7 PASS
- ruff OK / mypy OK / pytest 15 PASS, coverage 86.75%
- doc-drift 0 fail / adr-claims 77/77

Test infra: switched from `subprocess.run(["dbt", ...])` to
`dbt.cli.main.dbtRunner` so the fixtures work on Windows without venv
Scripts being on PATH. DuckDB rw-mode for both dbt + ml avoids the
"different configuration" connection error when both run in-process.

Co-authored-by: leagames0221-sys <leagames0221@users.noreply.github.com>
…#88)

Phase 4 of the data-analytics-demo bolt-on. Reads the SHAP summary that the
ML layer (#87) writes, sends a templated prompt to a local Ollama daemon,
and saves an executive-facing markdown narrative — never touching a cloud
LLM API.

What lands:
- narrative/ollama_client.py — env-var-gated host/model resolution
  (defaults: localhost:11434 + llama3.1:8b-instruct-q4_K_M), AC-4.3
  assertion that no cloud-LLM credentials are present at invocation, AC-4.2
  remediation hint when Ollama is unreachable.
- narrative/prompts.py — the executive-brief prompt template; SHAP-summary
  rendering is the only call point.
- narrative/generate.py — orchestration. Reads shap_summary.json, builds
  the prompt, calls Ollama, wraps the body with provenance metadata
  (model id, SHAP source path, timestamp, "external calls: 0"
  assertion-enforced advertisement) — satisfies AC-4.1, AC-4.4, AC-4.5.
- tests/test_narrative.py — 7 cases covering AC-4.1〜4.5 plus missing-data
  and prompt-builder paths. Uses monkeypatch to stub `ollama.Client` so no
  network is required in CI.
- Makefile narrative target + cli.py narrative subcommand wire-up.

AC coverage (mock-Ollama tests + real-Ollama smoke locally):
- AC-4.1 produces output.md     PASS
- AC-4.2 unreachable Ollama     PASS (clear RuntimeError with "ollama serve" hint)
- AC-4.3 external API guard     PASS (raises before any client call)
- AC-4.4 cites shap_summary.json PASS
- AC-4.5 model identifier in output PASS

Local verify:
- ruff OK / mypy OK (14 source files) / pytest 22 PASS / coverage 87.20%
- Real smoke vs Ollama (gemma3:4b, env-var override): 3-paragraph
  executive narrative produced end-to-end, all metadata fields present.

Design note: the literal AC-4.5 default model name is preserved as the
package default; deployments running a different quantized variant can
override via the OLLAMA_MODEL env var without code changes.

Co-authored-by: leagames0221-sys <leagames0221@users.noreply.github.com>
…Plotly (Evidence pivot) (#89)

Phase 5 of the data-analytics-demo bolt-on. Ships a static-HTML dashboard
generator that reads the dbt marts and emits 4 pages of charts + tables to
`dashboard/build/`.

Pivot from Evidence: the original Tradeoff 4 (ADR-0070) chose Evidence as
the BI tool. Local installation hit four+ chained peer-dependency failures
under pnpm 10 isolated layout and npm strict resolution (@sveltejs/kit,
vite, @evidence-dev/tailwind, ...). The fix path was unbounded and would
have introduced a second package manager into an otherwise-Python sub-tree
for a build-time-only artifact. ADR-0070 is amended in this PR with the
revised Tradeoff 4 and the rationale.

What lands:
- src/data_analytics_demo/dashboard/{__init__,render,queries,charts}.py
  Pure Python generator — reads from analytics.duckdb via duckdb-py,
  builds Plotly figures, renders Jinja2 templates.
- src/data_analytics_demo/dashboard/templates/{base,index,rfm,churn,kpi}.html.j2
  Layout (header / nav / metric strip / cards / footer) + 4 page templates.
- tests/test_dashboard.py — 4 cases covering AC-5.1〜5.4 (renders all
  pages; index contains all 3 required sections; uses the supplied
  DuckDB; missing-warehouse raises a clear error).
- Makefile + cli.py — `make dashboard` / `data-analytics-demo dashboard`
  now invoke the Python generator.
- pyproject.toml — adds jinja2 (BSD, Pallets) + plotly (MIT, Plotly Inc.)
  to dependencies; both already in the audited stack space.
- ADR-0070 amendment with the revised Tradeoff 4 and a "Why this is the
  better fit" narrative.

Local verify (Python 3.12 venv, seed=42):
- `make data` + `make dbt` + `make dashboard` end-to-end OK
- 4 pages produced: index.html (28KB), rfm.html (39KB), churn.html (12KB),
  kpi.html (38KB) — Plotly via CDN keeps per-page size small.
- ruff OK / mypy OK (19 source files) / pytest 26 PASS / coverage 88.31%
- doc-drift 0 fail / adr-claims 77/77 PASS

Co-authored-by: leagames0221-sys <leagames0221@users.noreply.github.com>
Phase 6 of the data-analytics-demo bolt-on. Ships the single source of
truth for KPI definitions and a validator that enforces the MetricFlow
schema invariants the rest of the package depends on.

What lands:
- semantic/kpi.yml — 3 semantic models (customers, subscriptions, invoices)
  and 4 metrics (customers, active_subscriptions, monthly_recurring_revenue,
  paid_invoice_volume). Each metric carries ≥ 1 dimension and ≥ 1 measure
  per AC-6.2.
- src/data_analytics_demo/semantic/validator.py — pure-Python validator.
  Parses the YAML, walks semantic_models[] / metrics[], and enforces:
  required keys, non-empty dims + measures, metric.measure references a
  declared measure, metric.dimensions all reference declared dimensions.
- tests/test_semantic.py — 5 cases covering AC-6.1 + AC-6.2 + negative
  paths (missing file, empty dim list, unknown measure ref) + canonical
  metric inventory.
- Makefile semantic-validate target + cli.py semantic subcommand wired up.
- types-PyYAML added to dev deps so mypy --strict sees the yaml stubs.

Local verify:
- `make semantic-validate` → "OK — 3 semantic models / 4 metrics: …"
- ruff OK / mypy OK (21 source files) / pytest 32 PASS / coverage 87.20%
- check-doc-drift / check-adr-claims unchanged (0 fail / 77/77)

Design note: the validator is independent of the MetricFlow CLI by design
— it enforces the structural invariants the package relies on without
shelling out to `mf validate-configs`, so the test suite has no CLI
dependency and runs cleanly under pytest.

Co-authored-by: leagames0221-sys <leagames0221@users.noreply.github.com>
…ners (#91)

Phase 7 of the data-analytics-demo bolt-on.

Makefile: `make demo` now prints a banner per stage (1/6 .. 6/6 + done) so
the stage boundaries are visible in long logs. Sub-makes run sequentially
inside a single recipe, so any non-zero exit halts the chain (AC-α.2).

tests/test_e2e_demo.py — 4 cases covering AC-α.1〜3 + AC-δ.1:
- Happy-path full pipeline: data → dbt → ml → narrative → dashboard →
  semantic-validate. Ollama is mocked at the client boundary so the test
  runs offline in CI. Asserts every expected artifact exists.
- Three negative-path cases enforce AC-α.2 at the Python-API surface:
  missing warehouse halts ml, missing shap_summary halts narrative,
  missing warehouse halts dashboard. Each raises a `FileNotFoundError`
  with a remediation hint.

The e2e test goes through the package's Python entry points rather than
shelling out to `make`, so the same coverage works on Windows + Linux
without depending on the shell.

Local verify:
- `make demo` end-to-end OK with banners visible at each stage
- `ruff` + `mypy --strict` clean (21 source files)
- `pytest` 36 passed (was 32; +4 e2e); coverage **87.20%**
- `check-doc-drift.mjs` 0 fail / `check-adr-claims.mjs` 77/77

Co-authored-by: leagames0221-sys <leagames0221@users.noreply.github.com>
…4 close-out) (#92)

Final phase of the data-analytics-demo bolt-on. Closes Stage 4 of the
Spec-Driven workflow (T-01〜T-14 — 14 / 14 tasks done across 8 PRs).

T-13 — Documentation:
- packages/data-analytics-demo/README.md: full rewrite. Quickstart in
  ≤ 5 commands (AC-ε.1), per-layer one-line architecture summary, layout
  table, constraints (load-bearing), engineered ML signals explanation.
- packages/data-analytics-demo/docs/architecture.md: mermaid pipeline
  diagram covering all 6 layers plus per-layer detail tables and the list
  of files produced by a full `make demo` run.

T-14 — Changelog + handoff:
- CHANGELOG.md (root): adds an Unreleased entry recording the
  data-analytics-demo 0.1.0 ship — six layers, CI infrastructure, security
  mitigations, test surface, all 8 PRs referenced. The package becomes
  the seventh `packages/*` entry and the monorepo's first Python sub-tree.
- HANDOFF.md (root): "Current" block flipped from "planning phase" to
  "shipped"; the verified-prior-art table superseded by the ADR-0070
  reference (it now lives in the design ADR, not in the ephemeral handoff).

Local verify:
- ruff OK / mypy OK (21 source files) / pytest 36 PASS / coverage 87.20%
- check-doc-drift 0 fail / check-adr-claims 77/77 PASS

Stage 4 done. The package can be developed and demoed end-to-end with a
single `make demo` invocation; recruiters can clone the repo and read all
three deliverables (SQL marts, ML + SHAP, dashboard + narrative) in
under five minutes.

Co-authored-by: leagames0221-sys <leagames0221@users.noreply.github.com>
…ar contract (#93)

Closes the AC-γ.3 drift surfaced by 2026-05-18 objective review:
- ADR-0070 L62 previously stated `.env.example ships placeholders only
  (deferred to T-03)`, but no `.env.example` was ever shipped (Security
  Master Layer 6 blocks the `.env*` filename pattern by design).
- The package's env-var surface (DEMO_* seed + row counts, OLLAMA_HOST /
  MODEL, prohibited cloud-LLM credentials) is genuinely documented; it
  just had no single source of truth.

This commit:
- Adds an "Environment variables" table to packages/data-analytics-demo/README.md
  (defaults match in-code constants; prohibited cloud-LLM credential
  list mirrors `ollama_client.EXTERNAL_API_ENV_VARS` exactly).
- Rewrites ADR-0070 security-mitigations bullet to reference the README
  section and enumerate the AC-4.3 fail-stop credential list explicitly.

Verify:
- ruff + mypy --strict: clean
- pytest: 36 PASS, coverage 87.20%
- doc-drift: 0 failure
- adr-claims: 77/77 PASS

Co-authored-by: leagames0221-sys <leagames0221@users.noreply.github.com>
…enforced floors (#94)

Documents the two CI-enforced floors (Churn ROC-AUC ≥ 0.70 via AC-3.2,
Upsell lift @ top-10% ≥ 1.5× via AC-3.7) with literal links to the
asserting test files and explanation of the seed-based reproduction
contract. External-facing portfolio copy can now cite this section
instead of presenting unsourced specific numbers.

Co-authored-by: leagames0221-sys <leagames0221@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
#95)

The Cron health step in `Live smoke` has been failing on every run
since the 2026-04-29 Gemini Free tier account-level revocation
incident (ADR-0067). EMERGENCY_STOP is the intended containment per
ADR-0046's kill-switch design — its existence is the structural
defense, and the smoke badge should reflect that the state is
intentional, not a regression.

Adds an ingest-endpoint probe before the threshold compare. If the
probe returns `{"code":"EMERGENCY_STOP"}` (the literal response from
apps/knowledge/src/lib/emergency-stop.ts when the env flag is set),
the gate downgrades from error to warning and exits 0, referencing
ADR-0067 in the workflow log. Under normal operation the gate stays
unchanged — `daysSinceLastGreenRun > 7` still fails the workflow.

Net effect:
- `Live smoke` returns to green while EMERGENCY_STOP is engaged
- `RAG eval` cron continues to fail as operator signal
  (the underlying problem — Gemini Free tier loss — is unchanged)
- When EMERGENCY_STOP lifts (post LLM-provider migration ratchet),
  the gate immediately re-engages without further code change

Co-authored-by: leagames0221-sys <leagames0221@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
leagames0221-sys and others added 2 commits May 18, 2026 15:15
The nightly RAG eval has been failing every run since the 2026-04-29
Gemini Free tier account-level revocation incident (ADR-0067), because
/api/kb/ingest returns 503 with {"code":"EMERGENCY_STOP"} under the
operator-active kill switch. The failure is the intended containment,
not a regression — same logic as PR #95 applied at the eval gate.

Adds an ingest-endpoint probe as the first step. If the probe returns
EMERGENCY_STOP, the remaining steps are skipped via step-level `if:`
conditions and the job exits green with a clear warning that references
ADR-0067. When EMERGENCY_STOP lifts (post LLM-provider migration
ratchet), the probe falls through and eval resumes its normal
regression-detection role with no further code change.

Net effect:
- `RAG eval` cron returns to green while EMERGENCY_STOP is engaged
- Eval log carries an explicit warning so any operator reading the run
  understands the deferred state and can find ADR-0067 in two clicks
- Eval still detects real regressions the moment the kill switch lifts

Co-authored-by: leagames0221-sys <leagames0221@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v4...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot @github

dependabot Bot commented on behalf of github May 21, 2026

Copy link
Copy Markdown
Contributor Author

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/checkout-6 branch May 21, 2026 17:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant