From 9dcf4769348055f4a1ea7f8206bd3797035f444e Mon Sep 17 00:00:00 2001 From: telivity-otaip Date: Thu, 20 Aug 2026 23:00:57 -0500 Subject: [PATCH 1/6] docs: add fixtures README for sample board pack --- docs/fixtures/README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 docs/fixtures/README.md diff --git a/docs/fixtures/README.md b/docs/fixtures/README.md new file mode 100644 index 0000000..e7c7232 --- /dev/null +++ b/docs/fixtures/README.md @@ -0,0 +1,17 @@ +# Fixtures + +## `sample-board-pack.json` + +**SEEDED / FICTIONAL** CareerOps board pack (`schema_version` 5) for demos and self-host smoke. + +- Fake companies only: Acme Corp, Northwind Traders, Contoso +- Includes roles across stages, accomplishments, one interview event, one contact +- API keys / secrets are never present (and would be stripped by `buildBoardPack` anyway) + +### Import + +Settings → **Your data** → import board pack → choose this file. + +Or from docs: see [BOARD_PACK.md](../BOARD_PACK.md). + +Do **not** replace this with a real personal board. From 555741d85d80735313a229ab5d5d4a4977a3a0db Mon Sep 17 00:00:00 2001 From: telivity-otaip Date: Thu, 20 Aug 2026 23:01:55 -0500 Subject: [PATCH 2/6] docs: add importable fictional sample board pack (schema v5) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Credit: @GabrielCanalli opened #33 — their fixture used the right demo companies but not the real board-pack shape, so Settings import loaded zero roles. This pack is produced via buildBoardPack. --- docs/fixtures/sample-board-pack.json | 159 +++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 docs/fixtures/sample-board-pack.json diff --git a/docs/fixtures/sample-board-pack.json b/docs/fixtures/sample-board-pack.json new file mode 100644 index 0000000..3d9d0c4 --- /dev/null +++ b/docs/fixtures/sample-board-pack.json @@ -0,0 +1,159 @@ +{ + "format": "careerops-board-pack/v5", + "schema_version": 5, + "exported_at": "2026-08-21T00:00:00.000Z", + "doctrine": { + "no_auto_apply": true, + "no_invented_facts": true, + "resume_struct_canonical": true, + "memory_provenance": true, + "no_auto_send": true + }, + "profile": { + "resume_struct": null, + "resume_struct_rev": 0, + "structured_modified_at": null, + "bullet_memory_cadence": "off", + "cadence_timezone": null, + "cadence_anchor": null, + "last_entry_at": null, + "target_band_min": 120000, + "target_band_max": 150000, + "target_band_currency": "USD" + }, + "stories": "SEEDED DEMO · FICTIONAL DATA — Acme checkout rewrite, Northwind inventory API.", + "find_prefs": null, + "roles": [ + { + "id": "seed-role-acme-fullstack", + "company": "Acme Corp", + "title": "Full Stack Developer", + "stage": "applied", + "url": "https://example.com/jobs/acme-fullstack", + "jd": "Build customer-facing APIs and a React dashboard. Paste real JDs in production — this text is fictional.", + "match_score": 78, + "ghost_risk": "low", + "level": "mid", + "location": "Remote · US", + "sent_at": "2026-07-20T15:00:00.000Z", + "comp_range": { + "min": 110000, + "max": 135000, + "currency": "USD", + "interval": "year", + "label": "USD 110k – 135k" + }, + "comp_raw": "USD 110k – 135k" + }, + { + "id": "seed-role-northwind-backend", + "company": "Northwind Traders", + "title": "Backend Engineer", + "stage": "interview", + "url": "https://example.com/jobs/northwind-backend", + "jd": "Own Postgres query paths and integration tests for inventory services. Fictional posting.", + "match_score": 84, + "ghost_risk": "unknown", + "level": "mid", + "location": "Hybrid", + "sent_at": null, + "comp_range": { + "min": 125000, + "max": 145000, + "currency": "USD", + "interval": "year", + "label": "USD 125k – 145k" + }, + "comp_raw": "USD 125k – 145k" + }, + { + "id": "seed-role-contoso-sourced", + "company": "Contoso", + "title": "Platform Engineer", + "stage": "sourced", + "url": "https://example.com/jobs/contoso-platform", + "jd": "CI/CD and internal developer platform. Fictional.", + "ghost_risk": "medium", + "level": "senior", + "location": "Remote", + "sent_at": null, + "comp_range": null, + "comp_raw": null + } + ], + "materials": [], + "reports": [], + "accomplishments": [ + { + "id": "seed-acc-1", + "body_original": "Refactored Acme checkout endpoints and cut p95 latency 35% (fictional metric for demo).", + "body_current": "Refactored Acme checkout endpoints and cut p95 latency 35% (fictional metric for demo).", + "revisions": [], + "status": "active", + "archived_at": null, + "role_id": null, + "employer": "Acme Corp", + "project": "Checkout rewrite", + "tags": ["performance", "api"], + "checked": true, + "promoted_role_id": null, + "promoted_bullet_id": null, + "promoted_at": null, + "promotion_snapshot": null, + "created_at": "2026-06-01T12:00:00.000Z", + "updated_at": "2026-06-01T12:00:00.000Z" + }, + { + "id": "seed-acc-2", + "body_original": "Added integration tests covering Northwind inventory write path (fictional).", + "body_current": "Added integration tests covering Northwind inventory write path (fictional).", + "revisions": [], + "status": "inbox", + "archived_at": null, + "role_id": null, + "employer": "Northwind Traders", + "project": "Inventory API", + "tags": ["testing"], + "checked": false, + "promoted_role_id": null, + "promoted_bullet_id": null, + "promoted_at": null, + "promotion_snapshot": null, + "created_at": "2026-06-15T12:00:00.000Z", + "updated_at": "2026-06-15T12:00:00.000Z" + } + ], + "portfolio": [], + "outcomes": {}, + "interview_events": [ + { + "id": "seed-iv-1", + "role_id": "seed-role-northwind-backend", + "round": 1, + "type": "screen", + "scheduled_at": "2026-08-10T18:00:00.000Z", + "notes": "Recruiter screen — fictional.", + "interviewer_name": "Alex Recruiter", + "created_at": null + } + ], + "contacts": [ + { + "id": "seed-contact-1", + "name": "Alex Recruiter", + "channel": "email", + "company": "Northwind Traders", + "role_ids": ["seed-role-northwind-backend"], + "last_touch_at": "2026-08-05T16:00:00.000Z", + "notes": "Fictional contact — outreach drafts only, never auto-send.", + "created_at": null + } + ], + "extensions": { + "plugins": [], + "fields": { + "seed_note": "SEEDED / FICTIONAL — public-safe sample for Settings → Import demos" + }, + "chain_runs": [] + } +} From eb8f61169f1d55eda83ccc6c425f4f38c0978b06 Mon Sep 17 00:00:00 2001 From: telivity-otaip Date: Thu, 20 Aug 2026 23:02:15 -0500 Subject: [PATCH 3/6] docs: link sample board pack from BOARD_PACK.md --- docs/BOARD_PACK.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/BOARD_PACK.md b/docs/BOARD_PACK.md index 597165b..76345d0 100644 --- a/docs/BOARD_PACK.md +++ b/docs/BOARD_PACK.md @@ -21,6 +21,10 @@ Schema migrations are implemented in ## Export and import +### Sample pack (fictional) + +Import [`fixtures/sample-board-pack.json`](fixtures/sample-board-pack.json) from **Settings → Your data** to populate a self-host board with seeded demo roles (Acme / Northwind / Contoso). Labeled **SEEDED / FICTIONAL** — no real PII, no API keys. + Board packs are created by `buildBoardPack` and read through `importBoardPack` in `web/lib/board-pack.mjs`. From e0cea2225ac09f6d1e3d5561552bd867f6c05ad5 Mon Sep 17 00:00:00 2001 From: telivity-otaip Date: Thu, 20 Aug 2026 23:02:16 -0500 Subject: [PATCH 4/6] test: cover sample board pack fixture import --- scripts/test-sample-board-pack.mjs | 39 ++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 scripts/test-sample-board-pack.mjs diff --git a/scripts/test-sample-board-pack.mjs b/scripts/test-sample-board-pack.mjs new file mode 100644 index 0000000..87c4ff4 --- /dev/null +++ b/scripts/test-sample-board-pack.mjs @@ -0,0 +1,39 @@ +#!/usr/bin/env node +/** + * Ensures docs/fixtures/sample-board-pack.json is a real v5 pack that imports roles. + */ +import assert from 'node:assert/strict' +import fs from 'node:fs' +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import { + importBoardPack, + planBoardPackUpsert, + BOARD_PACK_SCHEMA_VERSION, +} from '../web/lib/board-pack.mjs' + +const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..') +const fixturePath = path.join(root, 'docs/fixtures/sample-board-pack.json') + +assert.ok(fs.existsSync(fixturePath), 'docs/fixtures/sample-board-pack.json must exist') +const raw = JSON.parse(fs.readFileSync(fixturePath, 'utf8')) +assert.equal(raw.schema_version, BOARD_PACK_SCHEMA_VERSION) +assert.equal(raw.format, `careerops-board-pack/v${BOARD_PACK_SCHEMA_VERSION}`) +const blob = JSON.stringify(raw) +assert.doesNotMatch(blob, /openai_key|anthropic_key|api_key|sk-/i) + +const imported = importBoardPack(raw) +assert.ok(imported.roles.length >= 3, 'fixture must include demo roles') +assert.ok(imported.accomplishments.length >= 1) +const plan = planBoardPackUpsert(imported, { + existingRoleIds: [], + existingReportIds: [], + existingAccomplishmentIds: [], + existingPortfolioIds: [], + existingContactIds: [], +}) +assert.ok(plan.roles.insert.length >= 3) +assert.match(imported.stories || '', /FICTIONAL|SEEDED|Acme/i) + +console.log('ok sample board pack fixture imports roles (no secrets)') +console.log('\ntest-sample-board-pack passed') From 3c4f08934e281d03be3e714968da18dc6395843d Mon Sep 17 00:00:00 2001 From: telivity-otaip Date: Thu, 20 Aug 2026 23:02:41 -0500 Subject: [PATCH 5/6] chore: run sample board pack fixture test in npm test --- package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 4b440da..9848440 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "version": "1.2.1", "description": "CareerOps public repo — dashboard SPA + agent skill", "scripts": { - "test": "node scripts/privacy-scan.mjs && node scripts/smoke-web.mjs && node scripts/test-nav-sections.mjs && node scripts/test-board-layout.mjs && node scripts/test-find-match.mjs && node scripts/test-career-os.mjs && node scripts/test-schema-hardening.mjs && node scripts/test-promote-rpc.mjs && node scripts/test-credential-vault.mjs && node scripts/test-plugins.mjs && node scripts/test-chains.mjs && npm test --prefix packages/careerops", + "test": "node scripts/privacy-scan.mjs && node scripts/smoke-web.mjs && node scripts/test-nav-sections.mjs && node scripts/test-board-layout.mjs && node scripts/test-find-match.mjs && node scripts/test-career-os.mjs && node scripts/test-sample-board-pack.mjs && node scripts/test-schema-hardening.mjs && node scripts/test-promote-rpc.mjs && node scripts/test-credential-vault.mjs && node scripts/test-plugins.mjs && node scripts/test-chains.mjs && npm test --prefix packages/careerops", "test:web": "node scripts/smoke-web.mjs && node scripts/test-nav-sections.mjs && node scripts/test-board-layout.mjs", "test:nav": "node scripts/test-nav-sections.mjs", "test:board-layout": "node scripts/test-board-layout.mjs", @@ -22,7 +22,8 @@ "deploy": "bash scripts/deploy.sh", "deploy:functions": "bash scripts/deploy-functions.sh", "deploy:web": "bash scripts/deploy-web.sh", - "pack:careerops": "npm pack --prefix packages/careerops" + "pack:careerops": "npm pack --prefix packages/careerops", + "test:sample-pack": "node scripts/test-sample-board-pack.mjs" }, "devDependencies": { "playwright": "^1.62.0" From 1788b2e68d58e92e17de8ba2c888d3904e3c320f Mon Sep 17 00:00:00 2001 From: telivity-otaip Date: Thu, 20 Aug 2026 23:02:43 -0500 Subject: [PATCH 6/6] docs: link sample board pack from web README --- web/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/web/README.md b/web/README.md index 9af5cd9..e8f6fd9 100644 --- a/web/README.md +++ b/web/README.md @@ -44,6 +44,7 @@ Pure Career OS helpers used by the SPA live in `lib/` (bullet memory, cadence, r ### Export / import - **Board pack** (`CareerOps_board_pack.json`) — skill modes + Settings import (upsert). Schema v5 adds contacts, posted `comp_range`/`comp_raw`, and profile target band. API keys never exported or imported. +- **Sample pack** — import [`docs/fixtures/sample-board-pack.json`](../docs/fixtures/sample-board-pack.json) (SEEDED / FICTIONAL) from Settings → Your data to try a populated board without real job data. - See the [Board Pack schema changelog](../docs/BOARD_PACK.md) for the v1 → v5 schema details. - **Full JSON** / **CSV** — Settings → Your data.