feat(tracker-seed): seed script + payloads for engineering-review work items
Files the ENGINEERING_REVIEW_SCORECARD.md P0-P3 action plan as tracker items (one per affected product) via the platform-service POST /api/items API. Dependency-free Node seeder mints an HS256 token from $JWT_SECRET, dedupes by title, and supports --dry-run. No live writes performed (stack is down); run the script once the platform stack is up. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
257efcb4bc
commit
eb4e755c5f
49
scripts/tracker-seed/README.md
Normal file
49
scripts/tracker-seed/README.md
Normal file
@ -0,0 +1,49 @@
|
||||
# Tracker seed — Engineering Review work items
|
||||
|
||||
Files the `ENGINEERING_REVIEW_SCORECARD.md` P0–P3 action plan as **tracker items**
|
||||
(one per affected product) via the platform-service tracker API
|
||||
(`POST /api/items` — the same endpoint `tracker-web` proxies to).
|
||||
|
||||
## Files
|
||||
- `engineering-review-items.json` — the item payloads (16 items), scoped per `productId`.
|
||||
- `seed-tracker-items.mjs` — dependency-free Node script that mints an HS256
|
||||
token from `$JWT_SECRET` and POSTs each item (with dedupe-by-title).
|
||||
|
||||
## Prerequisites
|
||||
The platform stack must be running and reachable (it serves the tracker items API):
|
||||
|
||||
```bash
|
||||
# in learning_ai_common_plat (Cosmos emulator path)
|
||||
docker compose up -d # platform-service on :4003
|
||||
# …or run platform-service directly (ephemeral, no persistence):
|
||||
# DB_PROVIDER=memory COSMOS_ENDPOINT=x COSMOS_KEY=x JWT_SECRET=dev \
|
||||
# pnpm --dir services/platform-service dev
|
||||
```
|
||||
|
||||
## Usage
|
||||
```bash
|
||||
cd scripts/tracker-seed
|
||||
|
||||
# 1) Preview — no token, no network calls:
|
||||
node seed-tracker-items.mjs --dry-run
|
||||
|
||||
# 2) Create for real (uses the same JWT_SECRET platform-service verifies):
|
||||
JWT_SECRET="<shared-secret>" \
|
||||
PLATFORM_API_URL="http://localhost:4003" \
|
||||
node seed-tracker-items.mjs
|
||||
```
|
||||
|
||||
Re-running is safe: existing items are skipped by title per product (use
|
||||
`--force` to bypass the check). View results in `tracker-web` (`:3003`) under
|
||||
each product, or `GET /api/items?productId=<id>`.
|
||||
|
||||
## Env
|
||||
| Var | Default | Notes |
|
||||
|-----|---------|-------|
|
||||
| `PLATFORM_API_URL` | `http://localhost:4003` | platform-service base URL |
|
||||
| `JWT_SECRET` | — | required (unless `--dry-run`); must match platform-service |
|
||||
| `SEED_SUB` | `eng-review-bot` | token subject → `reportedBy` |
|
||||
| `SEED_ROLE` | `admin` | token role claim |
|
||||
| `ITEMS_FILE` | `engineering-review-items.json` | payload file |
|
||||
|
||||
Source of the items: `../../ENGINEERING_REVIEW_SCORECARD.md`.
|
||||
189
scripts/tracker-seed/engineering-review-items.json
Normal file
189
scripts/tracker-seed/engineering-review-items.json
Normal file
@ -0,0 +1,189 @@
|
||||
{
|
||||
"_meta": {
|
||||
"source": "ENGINEERING_REVIEW_SCORECARD.md (workspace review 2026-05-30)",
|
||||
"note": "One tracker item per affected product/area, derived from the P0-P3 action plan. productId values use the ByteLyst ecosystem slugs; standalone repos use a descriptive slug. Seed with seed-tracker-items.mjs.",
|
||||
"repoToProductId": {
|
||||
"learning_ai_common_plat / ecosystem infra": "platform",
|
||||
"learning_ai_devops_tools": "platform",
|
||||
"learning_voice_ai_agent": "lysnrai",
|
||||
"learning_multimodal_memory_agents": "mindlyst",
|
||||
"learning_ai_clock": "chronomind",
|
||||
"learning_ai_jarvis_jr": "jarvisjr",
|
||||
"learning_ai_fastgap": "nomgap",
|
||||
"learning_ai_peakpulse": "peakpulse",
|
||||
"learning_ai_flowmonk": "flowmonk",
|
||||
"learning_ai_notes": "notelett",
|
||||
"learning_ai_trails": "actiontrail",
|
||||
"learning_ai_local_memory_gpt": "localmemgpt",
|
||||
"learning_ai_efforise": "efforise",
|
||||
"learning_ai_2nd_brain": "secondbrain",
|
||||
"learning_ai_mac_tooling": "mactooling",
|
||||
"learning_ai_productivity_web": "productivityweb",
|
||||
"learning_ai_webui_copilot": "webuicopilot",
|
||||
"learning_agent_monitoring_fx": "agentmonitoring",
|
||||
"learning_ai_magic_clipboard_mgr": "magicclipboard"
|
||||
}
|
||||
},
|
||||
"items": [
|
||||
{
|
||||
"productId": "platform",
|
||||
"type": "task",
|
||||
"priority": "critical",
|
||||
"title": "[P0] Restore a working CI gate on learning_ai_common_plat",
|
||||
"description": "GitHub Actions is disabled (billing) on the platform monorepo that every product depends on; gitea CI exists but isn't an enforced gate. Re-enable GH Actions or make gitea CI the mandatory pre-merge gate. Ref: ENGINEERING_REVIEW_SCORECARD.md P0#1.",
|
||||
"labels": ["eng-review-2026-05", "p0", "ci", "platform"],
|
||||
"source": "internal",
|
||||
"visibility": "internal"
|
||||
},
|
||||
{
|
||||
"productId": "platform",
|
||||
"type": "task",
|
||||
"priority": "critical",
|
||||
"title": "[P0] Resolve ~14 dirty repos and add git upstreams",
|
||||
"description": "About 14 repos had uncommitted work / were behind origin at review time. Review+commit or discard intentionally, and add upstreams for learning_pytorch_todo_predictor and learning_sidecar_setup (currently no remote). Ref: scorecard P0#2.",
|
||||
"labels": ["eng-review-2026-05", "p0", "hygiene", "git"],
|
||||
"source": "internal",
|
||||
"visibility": "internal"
|
||||
},
|
||||
{
|
||||
"productId": "platform",
|
||||
"type": "task",
|
||||
"priority": "high",
|
||||
"title": "[P0] Define agent-queue daemon run policy (stop writing to live trees)",
|
||||
"description": "The agent-queue daemon + devin agents were running in --permission-mode dangerous and writing directly to live working trees, causing constant dirtiness and duplicate work landing upstream. Define a least-privilege, branch-per-task policy. Ref: scorecard P0#3 + SOP §8.",
|
||||
"labels": ["eng-review-2026-05", "p0", "agents", "devops"],
|
||||
"source": "internal",
|
||||
"visibility": "internal"
|
||||
},
|
||||
{
|
||||
"productId": "platform",
|
||||
"type": "task",
|
||||
"priority": "high",
|
||||
"title": "[P1] Add healthchecks + ordered depends_on to docker-compose.ecosystem.yml",
|
||||
"description": "The ecosystem compose orchestrates ~20 services with 30 restart policies and 24 build contexts but 0 healthcheck blocks. Add healthcheck to each backend/web service and depends_on: condition: service_healthy. Ref: scorecard D + P1#4.",
|
||||
"labels": ["eng-review-2026-05", "p1", "devops", "docker"],
|
||||
"source": "internal",
|
||||
"visibility": "internal"
|
||||
},
|
||||
{
|
||||
"productId": "platform",
|
||||
"type": "bug",
|
||||
"priority": "high",
|
||||
"title": "[P2] Remove NODE_TLS_REJECT_UNAUTHORIZED=0 and add rate-limiting to prototype APIs",
|
||||
"description": "TLS verification is disabled in some Docker setups; thin/zero input validation and no rate limiting in the Python prototype apps (webui_copilot, mac_tooling). Remove the TLS bypass where a real CA/host override exists and add rate limits. Ref: scorecard F + P2#10.",
|
||||
"labels": ["eng-review-2026-05", "p2", "security"],
|
||||
"source": "internal",
|
||||
"visibility": "internal"
|
||||
},
|
||||
{
|
||||
"productId": "platform",
|
||||
"type": "task",
|
||||
"priority": "low",
|
||||
"title": "[P3] Portfolio-wide coverage + dependency-audit in CI",
|
||||
"description": "Add coverage reporting and npm audit / pip-audit / cargo audit steps across the portfolio CI. Ref: scorecard P3#11.",
|
||||
"labels": ["eng-review-2026-05", "p3", "ci"],
|
||||
"source": "internal",
|
||||
"visibility": "internal"
|
||||
},
|
||||
{
|
||||
"productId": "platform",
|
||||
"type": "task",
|
||||
"priority": "low",
|
||||
"title": "[P3] Lightweight release/issue cadence for the 3 flagships (notelett, actiontrail, chronomind)",
|
||||
"description": "Pick the production-grade flagships and drive a real launch checklist + release cadence. Ref: scorecard G + P3#12.",
|
||||
"labels": ["eng-review-2026-05", "p3", "process"],
|
||||
"source": "internal",
|
||||
"visibility": "internal"
|
||||
},
|
||||
{
|
||||
"productId": "nomgap",
|
||||
"type": "task",
|
||||
"priority": "high",
|
||||
"title": "[P1] Stabilize E2E and remove continue-on-error (fastgap/nomgap)",
|
||||
"description": "Playwright E2E job is marked continue-on-error: true, so it isn't actually gating. Stabilize smoke E2E, then make it blocking. Ref: scorecard E + P1#5.",
|
||||
"labels": ["eng-review-2026-05", "p1", "testing", "e2e"],
|
||||
"source": "internal",
|
||||
"visibility": "internal"
|
||||
},
|
||||
{
|
||||
"productId": "flowmonk",
|
||||
"type": "task",
|
||||
"priority": "high",
|
||||
"title": "[P1] Stabilize E2E and remove continue-on-error (flowmonk)",
|
||||
"description": "Playwright E2E is non-gating (continue-on-error: true) and visual regression is excluded on Linux CI. Stabilize and make smoke E2E blocking. Ref: scorecard E + P1#5.",
|
||||
"labels": ["eng-review-2026-05", "p1", "testing", "e2e"],
|
||||
"source": "internal",
|
||||
"visibility": "internal"
|
||||
},
|
||||
{
|
||||
"productId": "jarvisjr",
|
||||
"type": "task",
|
||||
"priority": "high",
|
||||
"title": "[P1] Stabilize E2E and finish native surfaces (jarvisjr)",
|
||||
"description": "Playwright E2E is non-gating; watchOS/macOS in progress and Android (Phase 4) not started. Stabilize E2E and close out the 5 visible TODOs / native wiring. Ref: scorecard E/G.",
|
||||
"labels": ["eng-review-2026-05", "p1", "testing", "native"],
|
||||
"source": "internal",
|
||||
"visibility": "internal"
|
||||
},
|
||||
{
|
||||
"productId": "secondbrain",
|
||||
"type": "task",
|
||||
"priority": "medium",
|
||||
"title": "[P1] Replace 60+ print() calls with logging (learning_ai_2nd_brain)",
|
||||
"description": "CLI/intelligence modules use 60+ print() statements (violates the no-print rule). Switch to typer.echo/logging; keep behavior identical; run pytest. Ref: scorecard B + P1#6.",
|
||||
"labels": ["eng-review-2026-05", "p1", "code-quality"],
|
||||
"source": "internal",
|
||||
"visibility": "internal"
|
||||
},
|
||||
{
|
||||
"productId": "mactooling",
|
||||
"type": "task",
|
||||
"priority": "medium",
|
||||
"title": "[P2] Add tests, split 3k-line files, replace 200+ print() (learning_ai_mac_tooling)",
|
||||
"description": "Forensics toolkit has 0 tests, 200+ print() calls, and 3k+-line files (network_transfer_audit.py 3521, api_server.py 3116). Add a smoke test suite, split the large files, and move to logging. Ref: scorecard B/E + P2#9.",
|
||||
"labels": ["eng-review-2026-05", "p2", "code-quality", "testing"],
|
||||
"source": "internal",
|
||||
"visibility": "internal"
|
||||
},
|
||||
{
|
||||
"productId": "productivityweb",
|
||||
"type": "task",
|
||||
"priority": "medium",
|
||||
"title": "[P2] Add a test suite (learning_ai_productivity_web has 0 tests)",
|
||||
"description": "Clean client-only Next.js tool app with 0 tests and no CI. Add unit tests for the tools registry + a smoke test, and a CI job. Ref: scorecard E + P2#7.",
|
||||
"labels": ["eng-review-2026-05", "p2", "testing"],
|
||||
"source": "internal",
|
||||
"visibility": "internal"
|
||||
},
|
||||
{
|
||||
"productId": "webuicopilot",
|
||||
"type": "task",
|
||||
"priority": "medium",
|
||||
"title": "[P2] Add tests + CI + Docker (learning_ai_webui_copilot)",
|
||||
"description": "FastAPI + LangChain app with 0 tests, no CI, no Docker. Add pytest smoke tests for the rules/policy engines and a copilot happy-path, plus a CI job and Dockerfile. Ref: scorecard E/D + P2#7.",
|
||||
"labels": ["eng-review-2026-05", "p2", "testing", "devops"],
|
||||
"source": "internal",
|
||||
"visibility": "internal"
|
||||
},
|
||||
{
|
||||
"productId": "agentmonitoring",
|
||||
"type": "task",
|
||||
"priority": "medium",
|
||||
"title": "[P2] Add CI, cut console.log, finish native TODOs (learning_agent_monitoring_fx)",
|
||||
"description": "No CI; 54 console.log matches; 5 TODOs for native (KMP/iOS/Android) wiring; no Docker. Add CI, reduce logging noise, and close the native TODOs. Ref: scorecard B/D/G.",
|
||||
"labels": ["eng-review-2026-05", "p2", "code-quality", "devops"],
|
||||
"source": "internal",
|
||||
"visibility": "internal"
|
||||
},
|
||||
{
|
||||
"productId": "magicclipboard",
|
||||
"type": "task",
|
||||
"priority": "medium",
|
||||
"title": "[P2] Audit 50+ services for dead/stubbed code (learning_ai_magic_clipboard_mgr)",
|
||||
"description": "50+ service files with phase-named test buckets (Phase5-8, RemainingQATests) suggest AI-scaffold smell. Produce a report of wired vs stubbed services and consolidate. Ref: scorecard B + P2#8.",
|
||||
"labels": ["eng-review-2026-05", "p2", "code-quality", "audit"],
|
||||
"source": "internal",
|
||||
"visibility": "internal"
|
||||
}
|
||||
]
|
||||
}
|
||||
138
scripts/tracker-seed/seed-tracker-items.mjs
Normal file
138
scripts/tracker-seed/seed-tracker-items.mjs
Normal file
@ -0,0 +1,138 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Seed ByteLyst tracker items from a JSON payload file.
|
||||
*
|
||||
* Creates feature/bug/task items via the platform-service tracker API
|
||||
* (POST /api/items — the same endpoint tracker-web proxies to). Items are
|
||||
* scoped per `productId`. Use this to file the ENGINEERING_REVIEW_SCORECARD.md
|
||||
* P0-P3 work once the platform stack is running.
|
||||
*
|
||||
* Auth: mints a short-lived HS256 access token signed with $JWT_SECRET
|
||||
* (same secret platform-service verifies with). No external deps — uses
|
||||
* node:crypto only.
|
||||
*
|
||||
* Env:
|
||||
* PLATFORM_API_URL Base URL of platform-service (default http://localhost:4003)
|
||||
* JWT_SECRET Shared JWT secret (required unless --dry-run)
|
||||
* SEED_SUB Token subject / reportedBy (default "eng-review-bot")
|
||||
* SEED_EMAIL Token email claim (default "eng-review-bot@bytelyst.local")
|
||||
* SEED_ROLE Token role claim (default "admin")
|
||||
* ITEMS_FILE Payload file (default ./engineering-review-items.json)
|
||||
*
|
||||
* Flags:
|
||||
* --dry-run Print what would be created; no token, no network calls.
|
||||
* --force Skip the dedupe-by-title check.
|
||||
*
|
||||
* Examples:
|
||||
* node seed-tracker-items.mjs --dry-run
|
||||
* JWT_SECRET=... PLATFORM_API_URL=http://localhost:4003 node seed-tracker-items.mjs
|
||||
*/
|
||||
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { createHmac } from 'node:crypto';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { dirname, resolve } from 'node:path';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
const args = new Set(process.argv.slice(2));
|
||||
const DRY_RUN = args.has('--dry-run');
|
||||
const FORCE = args.has('--force');
|
||||
|
||||
const API = (process.env.PLATFORM_API_URL || 'http://localhost:4003').replace(/\/$/, '');
|
||||
const SECRET = process.env.JWT_SECRET || '';
|
||||
const SUB = process.env.SEED_SUB || 'eng-review-bot';
|
||||
const EMAIL = process.env.SEED_EMAIL || 'eng-review-bot@bytelyst.local';
|
||||
const ROLE = process.env.SEED_ROLE || 'admin';
|
||||
const ITEMS_FILE = resolve(__dirname, process.env.ITEMS_FILE || 'engineering-review-items.json');
|
||||
|
||||
function b64url(buf) {
|
||||
return Buffer.from(buf).toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
||||
}
|
||||
|
||||
/** Mint an HS256 access token compatible with @bytelyst/auth extractAuth(). */
|
||||
function mintToken() {
|
||||
if (!SECRET) throw new Error('JWT_SECRET must be set (or use --dry-run)');
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const header = { alg: 'HS256', typ: 'JWT' };
|
||||
const payload = { sub: SUB, email: EMAIL, role: ROLE, type: 'access', iat: now, exp: now + 3600 };
|
||||
const head = b64url(JSON.stringify(header));
|
||||
const body = b64url(JSON.stringify(payload));
|
||||
const sig = b64url(createHmac('sha256', SECRET).update(`${head}.${body}`).digest());
|
||||
return `${head}.${body}.${sig}`;
|
||||
}
|
||||
|
||||
async function listTitles(token, productId) {
|
||||
const url = `${API}/api/items?productId=${encodeURIComponent(productId)}&limit=500`;
|
||||
const res = await fetch(url, {
|
||||
headers: { authorization: `Bearer ${token}`, 'x-product-id': productId },
|
||||
});
|
||||
if (!res.ok) throw new Error(`list failed (${res.status})`);
|
||||
const data = await res.json();
|
||||
return new Set((data.items || []).map((i) => i.title));
|
||||
}
|
||||
|
||||
async function createItem(token, item) {
|
||||
const res = await fetch(`${API}/api/items`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
authorization: `Bearer ${token}`,
|
||||
'content-type': 'application/json',
|
||||
'x-product-id': item.productId,
|
||||
},
|
||||
body: JSON.stringify(item),
|
||||
});
|
||||
const text = await res.text();
|
||||
if (!res.ok) throw new Error(`${res.status} ${text.slice(0, 300)}`);
|
||||
return JSON.parse(text);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const raw = JSON.parse(readFileSync(ITEMS_FILE, 'utf8'));
|
||||
const items = raw.items || raw;
|
||||
console.log(`Loaded ${items.length} item(s) from ${ITEMS_FILE}`);
|
||||
console.log(`Target: ${API}/api/items (dry-run=${DRY_RUN}, force=${FORCE})\n`);
|
||||
|
||||
if (DRY_RUN) {
|
||||
for (const it of items) {
|
||||
console.log(` [DRY] ${it.productId.padEnd(16)} ${it.type}/${it.priority} ${it.title}`);
|
||||
}
|
||||
console.log(`\nDry run only — nothing sent. ${items.length} item(s) would be created.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const token = mintToken();
|
||||
const titleCache = new Map();
|
||||
let created = 0;
|
||||
let skipped = 0;
|
||||
let failed = 0;
|
||||
|
||||
for (const it of items) {
|
||||
try {
|
||||
if (!FORCE) {
|
||||
if (!titleCache.has(it.productId)) {
|
||||
titleCache.set(it.productId, await listTitles(token, it.productId).catch(() => new Set()));
|
||||
}
|
||||
if (titleCache.get(it.productId).has(it.title)) {
|
||||
console.log(` SKIP ${it.productId.padEnd(16)} ${it.title} (already exists)`);
|
||||
skipped++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const res = await createItem(token, it);
|
||||
console.log(` OK ${it.productId.padEnd(16)} ${res.id} ${it.title}`);
|
||||
created++;
|
||||
} catch (err) {
|
||||
console.error(` FAIL ${it.productId.padEnd(16)} ${it.title}\n ${err.message}`);
|
||||
failed++;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\nDone. created=${created} skipped=${skipped} failed=${failed}`);
|
||||
if (failed > 0) process.exit(1);
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error(`Fatal: ${err.message}`);
|
||||
process.exit(1);
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user