diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index c03de59..69271f0 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -183,7 +183,7 @@ {"id":"ge-hch.5.16.7","title":"Audit Logging \u0026 Telemetry Hooks","description":"Audit Logging \u0026 Telemetry Hooks\\n\\nShort summary: Implement integration audit logs and telemetry hook emission for observability.\\n\\nSuccess Criteria:\\n- Integration audit events emitted for proposal lifecycle stages and stored append-only (not embedded in saves by default).\\n- Telemetry events emitted conforming to telemetry schema and include PII-redaction where applicable.\\n- Operator can query integration logs by save id or player id in test harness.\\n\\nDeliverables:\\n- logging adapter to write append-only integration logs\\n- telemetry event emitters wired into hook points\\n- docs describing PII redaction and example queries\\n\\nOpen Questions:\\n- Retention and access model for integration logs (how long to keep, where to store). Recommend keeping short-term dev logs in local test harness and longer retention in external telemetry store; will coordinate with telemetry team.\\n","status":"closed","priority":1,"issue_type":"epic","assignee":"Build","created_at":"2026-01-18T17:14:20.613991773-08:00","created_by":"rgardler","updated_at":"2026-01-18T22:47:20.110458994-08:00","closed_at":"2026-01-18T22:47:20.110470044-08:00","labels":["milestone"],"dependencies":[{"issue_id":"ge-hch.5.16.7","depends_on_id":"ge-hch.5.16","type":"parent-child","created_at":"2026-01-18T17:14:20.615240667-08:00","created_by":"rgardler"},{"issue_id":"ge-hch.5.16.7","depends_on_id":"ge-hch.5.16.6","type":"blocks","created_at":"2026-01-18T17:14:21.058348541-08:00","created_by":"rgardler"}],"comments":[{"id":237,"issue_id":"ge-hch.5.16.7","author":"rgardler","text":"Audit \u0026 telemetry: basic telemetry subscriber implemented at src/runtime/subscribers/telemetry.js that logs via provided telemetry object (console in demo). Integration audit logging via persistence subscriber at src/runtime/subscribers/persistence.js (writes to .runtime_logs/integration.log). Demo persistence writes debug saves under src/.saves. Additional work: telemetry schema and PII redaction remain open. Changes in PR #180.","created_at":"2026-01-19T06:47:17Z"}]} {"id":"ge-hch.5.16.8","title":"QA, Fuzzing \u0026 E2E Tests","description":"QA, Fuzzing \u0026 E2E Tests\\n\\nShort summary: Provide unit tests, fuzzed save/load tests, and Playwright E2E smoke scenarios for mid-branch save/load and rollback.\\n\\nSuccess Criteria:\\n- Unit tests for state machine, checkpoint, and hook manager reach target coverage for new runtime modules (recommend ≥80% for these modules).\\n- Fuzz suite finds and reproduces rollback-inducing checkpoint corruptions.\\n- Playwright E2E tests: save mid-branch -\u003e reload -\u003e resume or graceful rollback pass locally.\\n\\nDeliverables:\\n- tests/unit/ for new runtime modules\\n- tests/fuzz/ harness and example failing cases captured for triage\\n- Playwright e2e test scripts and CI job suggestion notes\\n\\nOpen Questions:\\n- CI resource considerations for fuzz runs (how long to run, parallelization). Recommend short nightly fuzz runs initially; will tune based on results.\\n","status":"closed","priority":1,"issue_type":"epic","assignee":"Build","created_at":"2026-01-18T17:14:20.665062196-08:00","created_by":"rgardler","updated_at":"2026-01-18T22:47:22.183998424-08:00","closed_at":"2026-01-18T22:47:22.184011207-08:00","labels":["milestone"],"dependencies":[{"issue_id":"ge-hch.5.16.8","depends_on_id":"ge-hch.5.16","type":"parent-child","created_at":"2026-01-18T17:14:20.665714764-08:00","created_by":"rgardler"},{"issue_id":"ge-hch.5.16.8","depends_on_id":"ge-hch.5.16.7","type":"blocks","created_at":"2026-01-18T17:14:21.13016178-08:00","created_by":"rgardler"}],"comments":[{"id":238,"issue_id":"ge-hch.5.16.8","author":"rgardler","text":"QA \u0026 E2E: Unit tests for HookManager, state machine, checkpoint, and subscribers exist (tests/unit/*). Fuzz harness and Playwright E2E present; CI integration for fuzz/E2E should be configured separately. Branch ge-hch-5.16.1/reparent-to-ge-hch contains tests and demo. PR #180.","created_at":"2026-01-19T06:47:22Z"}]} {"id":"ge-hch.5.16.9","title":"Docs, Runbook \u0026 Handoff","description":"Docs, Runbook \u0026 Handoff\\n\\nShort summary: Finalize PRD updates, runtime docs, migration notes, and operator runbook for rollback and debugging.\\n\\nSuccess Criteria:\\n- Docs contain clear steps to read integration logs, force rollback in a test/dev environment, and migrate save versions.\\n- Developer docs show how to subscribe to hooks and use checkpoint API with code snippets.\\n- Handoff notes created for telemetry team and a changelog entry added to parent bead.\\n\\nDeliverables:\\n- docs/dev/runtime-hooks.md (usage examples), docs/runbook/rollback.md, migration notes in docs/dev/\\n- Handoff comment and changelog entry in parent bead\\n\\nOpen Questions:\\n- Who is the intended runbook owner for operational steps (recommend Build by default; change if you want a named owner).\\n","status":"closed","priority":1,"issue_type":"epic","assignee":"Build","created_at":"2026-01-18T17:14:20.716956186-08:00","created_by":"rgardler","updated_at":"2026-01-18T22:53:54.023531159-08:00","closed_at":"2026-01-18T22:53:54.023540693-08:00","labels":["milestone"],"dependencies":[{"issue_id":"ge-hch.5.16.9","depends_on_id":"ge-hch.5.16","type":"parent-child","created_at":"2026-01-18T17:14:20.717856366-08:00","created_by":"rgardler"},{"issue_id":"ge-hch.5.16.9","depends_on_id":"ge-hch.5.16.8","type":"blocks","created_at":"2026-01-18T17:14:21.183515324-08:00","created_by":"rgardler"}],"comments":[{"id":241,"issue_id":"ge-hch.5.16.9","author":"rgardler","text":"Docs \u0026 runbook added: docs/dev/runtime-hooks.md and docs/runbook/rollback.md created; README updated with demo testing steps. Handoff notes: recommend telemetry team owns telemetry schema/PII; created runtime-config and demo registration for persistence. Files in PR #180 on branch ge-hch-5.16.1/reparent-to-ge-hch.","created_at":"2026-01-19T06:53:49Z"}]} -{"id":"ge-hch.5.17","title":"Telemetry Implementation","description":"Implement telemetry event emission and collection for observability.\n\n## Scope\n- Implement 6 telemetry event types (generation, validation, director decision, presentation, choice, outcome)\n- Event emission at each pipeline stage\n- Privacy/redaction for sensitive data\n- **Player experience change**: Minimal direct change. System now collects data enabling future improvements. Optional: player can view a \"branch history\" summary showing AI vs authored content encountered in their playthrough.\n\n## Success Criteria\n- All 6 event types emit correctly in test environment\n- Events conform to telemetry schema\n- PII redaction applied before storage\n- Events can be queried for analysis\n- Player can optionally view summary of AI branches encountered in current session\n\n## Dependencies\n- Milestone 4: Runtime Integration \u0026 Hooks (ge-hch.5.16)\n\n## Deliverables\n- `src/telemetry/` module with event emitters\n- Telemetry configuration (retention, redaction rules)\n- Example dashboard queries\n- Optional player-facing branch history view","status":"in_progress","priority":1,"issue_type":"epic","assignee":"Build","created_at":"2026-01-16T13:23:19.188194703-08:00","created_by":"rgardler","updated_at":"2026-01-19T03:17:20.854320679-08:00","labels":["milestone","stage:idea","stage:in_progress"],"dependencies":[{"issue_id":"ge-hch.5.17","depends_on_id":"ge-hch.5","type":"parent-child","created_at":"2026-01-16T13:23:19.190188453-08:00","created_by":"rgardler"},{"issue_id":"ge-hch.5.17","depends_on_id":"ge-hch.5.16","type":"blocks","created_at":"2026-01-16T13:24:21.668183753-08:00","created_by":"rgardler"}]} +{"id":"ge-hch.5.17","title":"Telemetry Implementation","description":"Implement telemetry event emission and collection for observability.\n\n## Scope\n- Implement 6 telemetry event types (generation, validation, director decision, presentation, choice, outcome)\n- Event emission at each pipeline stage\n- Privacy/redaction for sensitive data\n- **Player experience change**: Minimal direct change. System now collects data enabling future improvements. Optional: player can view a \"branch history\" summary showing AI vs authored content encountered in their playthrough.\n\n## Success Criteria\n- All 6 event types emit correctly in test environment\n- Events conform to telemetry schema\n- PII redaction applied before storage\n- Events can be queried for analysis\n- Player can optionally view summary of AI branches encountered in current session\n\n## Dependencies\n- Milestone 4: Runtime Integration \u0026 Hooks (ge-hch.5.16)\n\n## Deliverables\n- `src/telemetry/` module with event emitters\n- Telemetry configuration (retention, redaction rules)\n- Example dashboard queries\n- Optional player-facing branch history view","status":"in_progress","priority":1,"issue_type":"epic","assignee":"@OpenCode","created_at":"2026-01-16T13:23:19.188194703-08:00","created_by":"rgardler","updated_at":"2026-01-19T23:06:24.135998971-08:00","labels":["milestone","stage:idea","stage:in_review"],"dependencies":[{"issue_id":"ge-hch.5.17","depends_on_id":"ge-hch.5","type":"parent-child","created_at":"2026-01-16T13:23:19.190188453-08:00","created_by":"rgardler"},{"issue_id":"ge-hch.5.17","depends_on_id":"ge-hch.5.16","type":"blocks","created_at":"2026-01-16T13:24:21.668183753-08:00","created_by":"rgardler"}],"comments":[{"id":248,"issue_id":"ge-hch.5.17","author":"@OpenCode","text":"Implemented basic telemetry module (emitter, redact, console backend). Added queryable in-memory buffer and README. Created feature branch feature/ge-hch.5.17-telemetry and pushed. Next: wire runtime hooks and emitters into src/runtime subscribers and add tests.","created_at":"2026-01-20T07:06:28Z"},{"id":249,"issue_id":"ge-hch.5.17","author":"@OpenCode","text":"Wired runtime hook subscribers to emit telemetry events (generation, presentation, pre/post checkpoint). Added NDJSON backend for dev ingestion and updated receiver to use it. Tests: unit suite passes locally. PR: https://github.com/TheWizardsCode/GEngine/pull/182","created_at":"2026-01-20T07:46:36Z"},{"id":250,"issue_id":"ge-hch.5.17","author":"@OpenCode","text":"Updated README for telemetry receiver to restore missing details and expand usage/examples. Next: add tests that verify telemetry emissions (buffer contents) and receiver ingestion (NDJSON file). Will add unit + integration tests that: 1) assert runtime hooks produce telemetry events in defaultTelemetry buffer; 2) start the receiver in a child process and POST a director_decision event, then assert events.ndjson contains the event.","created_at":"2026-01-20T07:49:34Z"},{"id":251,"issue_id":"ge-hch.5.17","author":"@OpenCode","text":"Added integration tests for telemetry emitter and receiver (NDJSON backend). README restored and expanded. PR updated: https://github.com/TheWizardsCode/GEngine/pull/182","created_at":"2026-01-20T07:50:26Z"}]} {"id":"ge-hch.5.18","title":"Policy \u0026 Sanitization Engine","description":"Implement the full validation pipeline with policy checks and sanitization transforms.\n\n## Scope\n- Implement policy ruleset engine (5 categories: content safety, narrative consistency, structure, format, return path)\n- Implement sanitization transforms (profanity redaction, HTML stripping, whitespace normalization)\n- Validation report generation with rule-level diagnostics\n- Replace minimal inline validator with full pipeline\n- **Player experience change**: Content quality noticeably improves. Inappropriate content blocked more reliably. Edge cases (odd formatting, encoding issues) no longer slip through. Players experience more polished AI-generated text.\n\n## Success Criteria\n- Policy engine evaluates proposals against configurable rulesets\n- Sanitization transforms are deterministic (same input → same output)\n- Validation reports conform to `validation-report.json` schema\n- Unit tests cover all policy categories and sanitization transforms\n- Player encounters no profanity, broken formatting, or encoding artifacts in AI content\n- Player experiences consistent text quality across AI branches\n\n## Dependencies\n- Milestone 5: Telemetry Implementation (ge-hch.5.17)\n\n## Deliverables\n- `src/validation/` module with policy engine and sanitizers\n- Configuration loader for policy rulesets\n- Validation report generator","status":"open","priority":1,"issue_type":"epic","assignee":"Build","created_at":"2026-01-16T13:23:30.97235286-08:00","created_by":"rgardler","updated_at":"2026-01-16T13:23:30.97235286-08:00","labels":["milestone","stage:idea"],"dependencies":[{"issue_id":"ge-hch.5.18","depends_on_id":"ge-hch.5","type":"parent-child","created_at":"2026-01-16T13:23:30.973289052-08:00","created_by":"rgardler"},{"issue_id":"ge-hch.5.18","depends_on_id":"ge-hch.5.17","type":"blocks","created_at":"2026-01-16T13:24:21.713979517-08:00","created_by":"rgardler"}]} {"id":"ge-hch.5.19","title":"Validation Test Corpus \u0026 Tuning","description":"Create a full-length test story and build test corpus to tune validation pipeline for production readiness.\n\n## Scope\n- Create new full-length story (`web/stories/test-story.ink`) with sufficient narrative variety for comprehensive testing\n- Keep `demo.ink` small for rapid playtesting\n- Create ≥100 example branch proposals for validation testing (generated against full test story)\n- Tune policy thresholds based on acceptance/rejection rates\n- Document ruleset rationale and tuning parameters\n- **Player experience change**: New full-length story available for involved testing. Better balance between safety and variety. Fewer \"good\" branches incorrectly rejected (more AI content available). Fewer \"bad\" branches incorrectly approved (higher quality). Players notice more frequent and more varied AI branch options across a complete narrative arc.\n\n## Success Criteria\n- New test story created with ≥10 scenes and varied narrative contexts\n- `demo.ink` remains small and unchanged (rapid playtesting)\n- Test corpus includes ≥100 proposals covering edge cases across the full test story\n- Validation pipeline passes ≥20 structured test cases\n- False positive rate \u003c5% on valid proposals\n- Tuning report documents threshold decisions\n- Player can experience a complete story arc in test story (beginning to end)\n- Player encounters AI branch options more frequently (reduced false rejections)\n- Player feedback indicates maintained or improved content quality\n\n## Dependencies\n- Milestone 6: Policy \u0026 Sanitization Engine (ge-hch.5.18)\n\n## Deliverables\n- New `web/stories/test-story.ink` (full-length story for testing)\n- Extended test corpus in `docs/dev/m2-schemas/examples/`\n- Validation test suite\n- Tuning report with threshold rationale","status":"open","priority":1,"issue_type":"epic","assignee":"Build","created_at":"2026-01-16T13:23:44.11356842-08:00","created_by":"rgardler","updated_at":"2026-01-16T13:23:44.11356842-08:00","labels":["milestone","stage:idea"],"dependencies":[{"issue_id":"ge-hch.5.19","depends_on_id":"ge-hch.5","type":"parent-child","created_at":"2026-01-16T13:23:44.114199912-08:00","created_by":"rgardler"},{"issue_id":"ge-hch.5.19","depends_on_id":"ge-hch.5.18","type":"blocks","created_at":"2026-01-16T13:24:21.755035562-08:00","created_by":"rgardler"}]} {"id":"ge-hch.5.2","title":"Secure: Telemetry webhook secret storage","description":"Create a bead to track securing the Discord webhook: CI secret creation, docs on local dev handling, and rotation plan.\\n\\n## Acceptance Criteria\\n- Bead documents where to store webhook (GitHub Actions secrets) and how to reference it in CI as TELEMETRY_WEBHOOK.\\n- Docs: docs/security/telemetry-webhook.md with minimal guidance.\\n","status":"closed","priority":2,"issue_type":"task","assignee":"Build","created_at":"2026-01-07T19:38:05.859182155-08:00","created_by":"rgardler","updated_at":"2026-01-16T02:09:46.733302782-08:00","closed_at":"2026-01-16T02:09:46.733302782-08:00","close_reason":"Auto-close: cleanup per status-skill","dependencies":[{"issue_id":"ge-hch.5.2","depends_on_id":"ge-hch.5","type":"parent-child","created_at":"2026-01-07T19:38:05.860089122-08:00","created_by":"rgardler"},{"issue_id":"ge-hch.5.2","depends_on_id":"ge-hch.3.1","type":"blocks","created_at":"2026-01-07T22:30:23.237557766-08:00","created_by":"rgardler"}],"comments":[{"id":168,"issue_id":"ge-hch.5.2","author":"rgardler","text":"Auto-closing per status-skill recommendation: no linked branches/PRs and not an epic. If this is incorrect, please reopen or add a comment.","created_at":"2026-01-16T10:09:46Z"}]} @@ -202,7 +202,7 @@ {"id":"ge-mud","title":"Make Ooda loop ouput fit the available screen width","status":"tombstone","priority":1,"issue_type":"task","assignee":"patch","created_at":"2026-01-16T22:21:19.755930775-08:00","created_by":"rgardler","updated_at":"2026-01-16T22:21:54.341660423-08:00","deleted_at":"2026-01-16T22:21:54.341660423-08:00","deleted_by":"daemon","delete_reason":"delete","original_type":"task"} {"id":"ge-ngf","title":"CI: Playwright E2E","description":"Add GitHub Actions workflow to run Playwright E2E tests.\\n\\nAcceptance criteria:\\n- Workflow file .github/workflows/playwright.yml runs on PRs and main.\\n- Workflow runs: npm ci, npx playwright install, npm test (demo e2e).\\n- On PR a job runs tests and reports status to PR.","status":"closed","priority":1,"issue_type":"task","assignee":"rgardler","created_at":"2026-01-06T23:08:53.428619454-08:00","created_by":"rgardler","updated_at":"2026-01-07T02:20:17.470750673-08:00","closed_at":"2026-01-07T02:20:17.470750673-08:00","close_reason":"Closed"} {"id":"ge-nzz","title":"Make root README InkJS-only","description":"Remove Unity references from the root README.md and focus it on InkJS/web demo usage and tests.","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-06T15:12:16.621516991-08:00","created_by":"rgardler","updated_at":"2026-01-06T15:13:37.065401561-08:00","closed_at":"2026-01-06T15:13:37.065401561-08:00","close_reason":"Done"} -{"id":"ge-okh","title":"Add npm script + docs to run embedding integration test","description":"Add an npm script to run the real-model embedding integration test (EMBED_NODE=1). Include a short note in web/demo/README.md describing the script and how to run it locally.\\n\\nAcceptance criteria:\\n- package.json has script that runs: \\n- web/demo/README.md contains a 1-2 line note explaining the script and env flags\\n- Tests: running the script locally succeeds (developer responsibility)\\n\\nFiles to be changed: , ","status":"open","priority":2,"issue_type":"task","created_at":"2026-01-17T20:47:17.395948499-08:00","created_by":"rgardler","updated_at":"2026-01-17T20:47:17.395948499-08:00","labels":["stage:idea"]} +{"id":"ge-okh","title":"Add npm script + docs to run embedding integration test","description":"Add an npm script to run the real-model embedding integration test (EMBED_NODE=1). Include a short note in web/demo/README.md describing the script and how to run it locally.\\n\\nAcceptance criteria:\\n- package.json has script that runs: \\n- web/demo/README.md contains a 1-2 line note explaining the script and env flags\\n- Tests: running the script locally succeeds (developer responsibility)\\n\\nFiles to be changed: , ","status":"open","priority":2,"issue_type":"task","created_at":"2026-01-17T20:47:17.395948499-08:00","created_by":"rgardler","updated_at":"2026-01-17T20:47:17.395948499-08:00","labels":["stage:idea"],"dependencies":[{"issue_id":"ge-okh","depends_on_id":"ge-hch.5","type":"parent-child","created_at":"2026-01-19T23:01:36.648476327-08:00","created_by":"Ross Gardler"}]} {"id":"ge-oow","title":"Refactor: remove jq fallback for replay failure JSON","description":"### Goal\\nRemove the -based fallback in that synthesizes failure JSON from logs. The replay runner now writes structured JSON via ; the workflow should rely on that structured output instead of reconstructing it from logs.\\n\\n### Acceptance Criteria\\n- The workflow no longer runs to synthesize .\\n- The workflow copies or uploads the runner-produced (or a runner-produced failure file) into artifacts/results and archives it for failing runs.\\n- A CI run for the PR demonstrates a failing replay produces an uploaded visible in the job artifacts.\\n- Files touched are limited to (and any small adjustments to only if strictly necessary).\\n\\n### Suggested Implementation\\n1. Edit to remove the fallback block and instead rely on produced by the runner.\\n2. Ensure the workflow still copies raw logs and uploads \u0026 .\\n3. Run CI on a PR that intentionally fails a replay to confirm artifact presence.\\n\\n### Timebox\\nEstimate: 1-2 hours.\\n\\n### Notes\\n- Keep an eye on edge cases where runner result is missing; if this proves to happen, we may want a minimal guard that reports a clear error but does not attempt to reconstruct the JSON.\\n\\n### Related\\ndiscovered-from:ge-hch.4.3\\n","status":"closed","priority":3,"issue_type":"task","assignee":"rgardler","created_at":"2026-01-16T00:32:00.440882328-08:00","created_by":"rgardler","updated_at":"2026-01-16T01:38:44.850810587-08:00","closed_at":"2026-01-16T01:38:44.850810587-08:00","close_reason":"Completed: removed jq fallback; PR #151 merged","dependencies":[{"issue_id":"ge-oow","depends_on_id":"ge-hch.4.3","type":"discovered-from","created_at":"2026-01-16T00:32:00.453040701-08:00","created_by":"rgardler"}],"comments":[{"id":156,"issue_id":"ge-oow","author":"rgardler","text":"Created branch ge-oow/remove-jq-fallback and opened PR #151 to remove jq fallback; change uses printf to emit minimal failure JSON if runner result is missing. Marking as in_progress and assigned to rgardler.","created_at":"2026-01-16T09:34:53Z"},{"id":157,"issue_id":"ge-oow","author":"rgardler","text":"Merged PR #151: removed jq fallback and emit minimal failure JSON using printf. Verified replay artifacts show no failures for this change. Closing bead.","created_at":"2026-01-16T09:38:43Z"}]} {"id":"ge-osd","title":"Restore original demo story for smoke tests","status":"closed","priority":1,"issue_type":"bug","created_at":"2026-01-06T22:09:37.056596959-08:00","created_by":"rgardler","updated_at":"2026-01-06T22:10:00.371743266-08:00","closed_at":"2026-01-06T22:10:00.371743266-08:00","close_reason":"Done","comments":[{"id":1,"issue_id":"ge-osd","author":"rgardler","text":"Fixed smoke tests broken by demo story changes by adding web/stories/test.ink (pre-903f044 demo story) and routing /stories/demo.ink to that file in Playwright.\n\nChanges:\n- web/stories/test.ink\n- tests/demo.smoke.spec.ts\n\nCommands:\n- npm test","created_at":"2026-01-07T06:09:54Z"}]} {"id":"ge-qip","title":"Parent: Test parent/child relationship","description":"escription","status":"tombstone","priority":2,"issue_type":"epic","owner":"ross@gardler.org","created_at":"2026-01-19T18:38:38.077369615-08:00","created_by":"Ross Gardler","updated_at":"2026-01-19T18:41:54.055362933-08:00","deleted_at":"2026-01-19T18:41:54.055362933-08:00","deleted_by":"daemon","delete_reason":"delete","original_type":"epic"} diff --git a/.beads/sync_base.jsonl b/.beads/sync_base.jsonl index b844aff..4903e99 100644 --- a/.beads/sync_base.jsonl +++ b/.beads/sync_base.jsonl @@ -1,5 +1,5 @@ {"id":"ge-02n","title":"Duplicate Playwright runs on PRs — investigation","description":"Summary:\\n\\nOn recent PRs Playwright E2E is running twice: once from .github/workflows/pr-ci.yml (job 'playwright') and once from .github/workflows/playwright.yml (separate workflow that triggers on pull_request).\\n\\nDiagnosis:\\n\\n- pr-ci.yml defines a 'playwright' job that runs Playwright tests for pull_request events (lines ~40-70).\\n- playwright.yml is a standalone workflow that also triggers on pull_request and runs Playwright tests (it contains change detection and a 'tests' job)\\n- Both files include pull_request triggers with no mutually-exclusive conditions, so a PR will cause both workflows to run, producing duplicate CI runs.\\n\\nSuggested fixes (pick one):\\n\\n1) Remove the 'playwright' job from pr-ci.yml (recommended): keep a single Playwright workflow in playwright.yml.\\n - Pros: simplest change; centralises Playwright logic and reporting.\\n - Cons: pr-ci.yml will no longer show Playwright step inline; reviewers lose single-workflow view.\\n\\n2) Disable or narrow the pull_request trigger in playwright.yml: change it to workflow_dispatch only, or add types/paths so it doesn't run for all PRs.\\n - Pros: pr-ci.yml remains an all-in-one PR workflow.\\n - Cons: duplicate logic may remain; risk of divergence over time.\\n\\n3) Scope triggers by paths or add an explicit if: keep both workflows but ensure only one runs depending on changed files (e.g., run Playwright workflow only when web/ or src/ change).\\n - Pros: preserves intent of both workflows and avoids unnecessary runs.\\n - Cons: slightly more complex; needs careful testing of path rules.\\n\\nAcceptance criteria (definition of done):\\n\\n- Only one Playwright test run appears per PR for normal PRs that change code (no duplicate GitHub Action runs).\\n- Test artifacts (reports, junit, etc.) are still uploaded and accessible.\\n- No loss of required checks for PR merges.\\n- A short note in repo docs or PR that explains the change.\\n\\nFiles touched (candidates for edits):\\n- .github/workflows/pr-ci.yml (remove or change 'playwright' job)\n- .github/workflows/playwright.yml (narrow trigger or keep as canonical Playwright runner)\n- Optional: .github/README or CONTRIBUTING noting CI layout\\n\\nIf you'd like, I can create a bd issue and propose a specific change with a patch (one-line edit to drop the playwright job), or just explain and leave files unchanged.\\n\\nReferences: lines reviewed in: .github/workflows/pr-ci.yml, .github/workflows/playwright.yml, .github/workflows/validate-story.yml (also has similar detection logic)\\n\\n,--json:false}","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-14T20:04:45.001482767-08:00","created_by":"rgardler","updated_at":"2026-01-14T20:52:15.156552285-08:00","closed_at":"2026-01-14T20:52:15.156558194-08:00","comments":[{"id":128,"issue_id":"ge-02n","author":"rgardler","text":"Investigation complete — PR #138 merged and change deployed. Closing this investigation. See PR: https://github.com/TheWizardsCode/GEngine/pull/138","created_at":"2026-01-15T04:36:13Z"},{"id":130,"issue_id":"ge-02n","author":"rgardler","text":"Investigation closed: Playwright duplicate runs resolved in merged PR #138. Note: local ancestry check shows branch 'ge-02n/remove-playwright-job' is NOT an ancestor of origin/main — merged changes appear to have come from a different branch/PR. Left the branch intact to avoid accidental deletion. Please confirm if branch can be deleted. Commands run: git fetch origin --prune; git checkout main; git pull --rebase; git merge-base --is-ancestor ge-02n/remove-playwright-job origin/main (NOT merged).","created_at":"2026-01-15T04:37:28Z"},{"id":132,"issue_id":"ge-02n","author":"rgardler","text":"Created rebased copy of branch ge-02n/remove-playwright-job as ge-02n/rebased/remove-playwright-job. Steps performed: fetched origin, backed up original branch to ge-02n/remove-playwright-job.backup, rebased onto origin/main, committed bd export, and pushed new branch. Rebase succeeded with no conflicts. Remote branch: origin/ge-02n/rebased/remove-playwright-job\\n\\nRecommended next step: open a PR from ge-02n/rebased/remove-playwright-job to main for review/merge.\\n\\nRebase result: commits on rebased branch (vs origin/main):\\n- c1e64a0 chore(bd): export bd sync for ge-02n rebased branch\\n- c07f5f7 chore: bd updates — close duplicate-playwright investigation (ge-02n)\\n- 567a057 bd sync: 2026-01-14 20:09:45\\n- dee5230 ci: remove Playwright job from pr-ci.yml (use playwright.yml\\n\\nBranch URL: https://github.com/TheWizardsCode/GEngine/tree/ge-02n/rebased/remove-playwright-job","created_at":"2026-01-15T04:46:06Z"},{"id":134,"issue_id":"ge-02n","author":"rgardler","text":"Deleted local backup branch ge-02n/remove-playwright-job.backup per user request. Rebassed branch ge-02n/rebased/remove-playwright-job and PR #139 remain.","created_at":"2026-01-15T04:49:44Z"},{"id":136,"issue_id":"ge-02n","author":"rgardler","text":"Final cleanup: PR #139 merged and rebased branch deleted. Close out investigation.","created_at":"2026-01-15T04:51:02Z"},{"id":137,"issue_id":"ge-02n","author":"rgardler","text":"Final: investigation and cleanup complete. PRs #138 and #139 merged, duplicate Playwright job removed, branches cleaned up. Closing investigation.","created_at":"2026-01-15T04:52:15Z"}]} -{"id":"ge-0y6","title":"Telemetry ingestion prototype (ingest endpoint)","description":"Create a lightweight telemetry ingestion prototype to receive director_decision events.\\n\\nAcceptance criteria:\\n- Implement a simple HTTP POST endpoint at server/telemetry/receiver.js that accepts director_decision events and persists them to a SQLite DB or newline-delimited JSON file.\\n- Endpoint responds 200 on valid payload and returns 400 on invalid payload.\\n- Add minimal README at server/telemetry/README.md describing how to run the receiver locally and how to test with curl.\\n- Create bd comments referencing files changed and example curl commands.\\n- Link bead as child of ge-hch.5.17 (Telemetry Implementation) and assign to @rgardler.\\n\\nFiles likely changed/created:\\n- server/telemetry/receiver.js\\n- server/telemetry/README.md\\n- server/telemetry/package.json (optional)\\n\\nNotes:\\n- This is a prototype for dev/testing only; do not include production hardening. Use minimal dependencies (node + express or native http).\\n","status":"in_progress","priority":1,"issue_type":"task","assignee":"@rgardler","created_at":"2026-01-17T12:54:12.943457918-08:00","created_by":"rgardler","updated_at":"2026-01-19T12:58:52.221500188-08:00","external_ref":"https://github.com/TheWizardsCode/GEngine/pull/181","labels":["Status: PR Created","Status: PR Merged","stage:idea","stage:in_review"],"dependencies":[{"issue_id":"ge-0y6","depends_on_id":"ge-hch.5.17","type":"parent-child","created_at":"2026-01-17T12:54:17.715877028-08:00","created_by":"rgardler"}],"comments":[{"id":242,"issue_id":"ge-0y6","author":"@OpenCode","text":"Created PR https://github.com/TheWizardsCode/GEngine/pull/181. Files changed: server/telemetry/receiver.js, server/telemetry/README.md. Example curl to test: \\n\\n curl -X POST -H 'Content-Type: application/json' -d '{\"type\":\"director_decision\",\"decision\":\"accept\"}' http://localhost:4005/\\n\\nStarted server locally and confirmed events are appended to server/telemetry/events.ndjson.","created_at":"2026-01-19T11:21:19Z"},{"id":243,"issue_id":"ge-0y6","author":"@scribble","text":"Updated server/telemetry/README.md to include purpose, example payload shape, and next-step suggestions (SQLite, schema validation, auth).","created_at":"2026-01-19T20:57:30Z"},{"id":244,"issue_id":"ge-0y6","author":"@OpenCode","text":"PR merged: https://github.com/TheWizardsCode/GEngine/pull/181 (merge commit 9abdcc09d6d). Leaving bead open until follow-ups complete. Updated label: Status: PR Merged.","created_at":"2026-01-19T20:58:52Z"}]} +{"id":"ge-0y6","title":"Telemetry ingestion prototype (ingest endpoint)","description":"Create a lightweight telemetry ingestion prototype to receive director_decision events.\\n\\nAcceptance criteria:\\n- Implement a simple HTTP POST endpoint at server/telemetry/receiver.js that accepts director_decision events and persists them to a SQLite DB or newline-delimited JSON file.\\n- Endpoint responds 200 on valid payload and returns 400 on invalid payload.\\n- Add minimal README at server/telemetry/README.md describing how to run the receiver locally and how to test with curl.\\n- Create bd comments referencing files changed and example curl commands.\\n- Link bead as child of ge-hch.5.17 (Telemetry Implementation) and assign to @rgardler.\\n\\nFiles likely changed/created:\\n- server/telemetry/receiver.js\\n- server/telemetry/README.md\\n- server/telemetry/package.json (optional)\\n\\nNotes:\\n- This is a prototype for dev/testing only; do not include production hardening. Use minimal dependencies (node + express or native http).\\n","status":"closed","priority":1,"issue_type":"task","assignee":"@rgardler","created_at":"2026-01-17T12:54:12.943457918-08:00","created_by":"rgardler","updated_at":"2026-01-19T15:41:10.945498705-08:00","closed_at":"2026-01-19T15:41:10.945498705-08:00","close_reason":"Merged: receiver prototype; follow-ups tracked in ge-apq/geo-apq.1","external_ref":"https://github.com/TheWizardsCode/GEngine/pull/181","labels":["Status: PR Created","Status: PR Merged","stage:idea","stage:in_review"],"dependencies":[{"issue_id":"ge-0y6","depends_on_id":"ge-hch.5.17","type":"parent-child","created_at":"2026-01-17T12:54:17.715877028-08:00","created_by":"rgardler"}],"comments":[{"id":242,"issue_id":"ge-0y6","author":"@OpenCode","text":"Created PR https://github.com/TheWizardsCode/GEngine/pull/181. Files changed: server/telemetry/receiver.js, server/telemetry/README.md. Example curl to test: \\n\\n curl -X POST -H 'Content-Type: application/json' -d '{\"type\":\"director_decision\",\"decision\":\"accept\"}' http://localhost:4005/\\n\\nStarted server locally and confirmed events are appended to server/telemetry/events.ndjson.","created_at":"2026-01-19T11:21:19Z"},{"id":243,"issue_id":"ge-0y6","author":"@scribble","text":"Updated server/telemetry/README.md to include purpose, example payload shape, and next-step suggestions (SQLite, schema validation, auth).","created_at":"2026-01-19T20:57:30Z"},{"id":244,"issue_id":"ge-0y6","author":"@OpenCode","text":"PR merged: https://github.com/TheWizardsCode/GEngine/pull/181 (merge commit 9abdcc09d6d). Leaving bead open until follow-ups complete. Updated label: Status: PR Merged.","created_at":"2026-01-19T20:58:52Z"}]} {"id":"ge-1qd","title":"Track .beads/issues.jsonl in repo to enable bd sync","status":"closed","priority":1,"issue_type":"chore","created_at":"2026-01-03T00:38:09.856060926-08:00","created_by":"rgardler","updated_at":"2026-01-03T01:36:09.196632851-08:00","closed_at":"2026-01-03T01:36:09.196632851-08:00"} {"id":"ge-1x8","title":"Wrap-up: handoff notes and follow-ups (telemetry & CI)","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-07T01:23:49.255685142-08:00","created_by":"rgardler","updated_at":"2026-01-07T02:20:17.460720304-08:00","closed_at":"2026-01-07T02:20:17.460720304-08:00","close_reason":"Closed","dependencies":[{"issue_id":"ge-1x8","depends_on_id":"ge-hch.1.6","type":"discovered-from","created_at":"2026-01-07T01:23:49.267228872-08:00","created_by":"rgardler"}]} {"id":"ge-2b0","title":"CI: limit Playwright E2E on main","description":"Policy decision: Run Playwright E2E on PRs only. Keep a scheduled main run (nightly) and an optional gated run tied to GitHub Pages deploys for post-deploy validation.\\n\\nRationale:\\n- Reduce redundant costly CI runs on push-to-main while keeping safety via PR checks and periodic validation on main.\\n\\nImplementation plan (Ship):\\n1) Update .github/workflows/playwright.yml:\\n - Remove or disable the 'push' trigger for main (or add a path filter) so it no longer runs on every push-to-main.\\n - Ensure it runs on 'pull_request' and 'workflow_dispatch'.\\n - Add a scheduled cron job entry (e.g., nightly) in the workflow or create a separate workflow that runs Playwright on main nightly.\\n - Preserve artifact upload behavior on failure (no change needed unless altered).\\n2) Optionally add a small gated workflow to run Playwright after GitHub Pages deploy (or as part of the gh-pages workflow) if you want post-deploy validation.\\n3) Update docs: add a short note to docs/InkJS_README.md or docs/CI_RUNBOOK.md describing the Playwright policy and how to manually trigger runs.\\n\\nAcceptance criteria (Definition of Done):\\n- Playwright workflow triggers on PRs and no longer triggers on ordinary pushes to main.\\n- Nightly scheduled Playwright run exists and completes (or is configured) for main.\\n- Artifact upload on failure still occurs in PRs and scheduled runs.\\n- A bd comment on this bead documents the branch name used, PR URL (if created), or workflow run IDs demonstrating the new behavior.\\n\\nConstraints / Notes:\\n- Do NOT force-push or rewrite history on main. Create a feature branch (suggested: ge-2b0/playwright-prs-only) and open a PR.\\n- If any unexpected CI gating or GitHub permission issues arise, report back in this bead before proceeding.\\n\\nAssignee: Ship (please implement).\\n,json:true","status":"closed","priority":1,"issue_type":"task","assignee":"Ship","created_at":"2026-01-08T01:03:53.611971564-08:00","created_by":"rgardler","updated_at":"2026-01-14T01:32:50.501205364-08:00","closed_at":"2026-01-14T01:32:50.501212517-08:00","dependencies":[{"issue_id":"ge-2b0","depends_on_id":"ge-hch.3.3","type":"discovered-from","created_at":"2026-01-08T01:03:53.631932094-08:00","created_by":"rgardler"}],"comments":[{"id":32,"issue_id":"ge-2b0","author":"rgardler","text":"Linked from ge-hch.3.3: user request to prevent Playwright E2E runs on pushes to main. Capture policy (PR-only, paths filter, label gate) and adjust workflow.","created_at":"2026-01-08T09:04:03Z"},{"id":87,"issue_id":"ge-2b0","author":"rgardler","text":"Blocked: cannot create branch ge-2b0/playwright-prs-only from origin/main because local changes would be overwritten. Git status shows:\\n\\n M .beads/issues.jsonl\\n M AGENTS.md\\n\\nOptions for how to proceed (please choose):\\nA) Stash local changes, create branch from origin/main, implement CI edits, then pop stash (recommended if you want a clean branch from main).\\nB) Create the feature branch from the current branch (ge-rw4/commit-agent-docs) so the agent-doc edits are included; proceed with CI edits on that branch and open PR from it.\\nC) Commit the local changes to the current branch and then create the new branch from origin/main (requires committing or stashing first).\\n\\nPlease reply with A, B, or C (or provide alternate instruction). I will proceed once you confirm.","created_at":"2026-01-14T08:29:22Z"},{"id":88,"issue_id":"ge-2b0","author":"rgardler","text":"PR created: https://github.com/TheWizardsCode/GEngine/pull/131 (ge-2b0). Ship implemented: run Playwright on PRs only (removed push:main), added nightly scheduled workflow playwright-nightly.yml. Pending validation after merge. ","created_at":"2026-01-14T08:31:54Z"},{"id":91,"issue_id":"ge-2b0","author":"rgardler","text":"Attempted to update local main but checkout failed due to local changes.\n\nSteps run:\n- git fetch origin\n- git checkout main <-- FAILED\n\nObserved output during attempt:\n\n$(git fetch origin 2>&1 || true)\n\nCheckout error: Your local changes to the following files would be overwritten by checkout: .beads/issues.jsonl\n\nCaptured git state after failure:\n\nCurrent HEAD branch:\n$(cat /tmp/head.txt)\n\nLast commit:\n$(cat /tmp/last_commit.txt)\n\nWorking tree status (porcelain):\n$(cat /tmp/git_status.txt)\n\nAction taken: Stopped further steps to avoid overwriting uncommitted .beads/issues.jsonl (allowed exception in agent rules). Please advise whether to stash/commit the .beads changes or proceed on current branch.\n\nI will not perform any destructive git operations.\n","created_at":"2026-01-14T08:37:50Z"},{"id":92,"issue_id":"ge-2b0","author":"rgardler","text":"PR merged: https://github.com/TheWizardsCode/GEngine/pull/131\n\nGit outputs (after syncing and switching to main):\nBranch: main\nLast commit: 480e10e Simplify agent definitions by moving common items to AGENTS.md. Better default permissions for build.md. Clearer delegation path. (#132)\nStatus:\n\nbd sync output:\n✓ Sync complete\n\nNotes:\n- Playwright PR (#131) merged; nightly workflow added (.github/workflows/playwright-nightly.yml).\n- Awaiting workflow run IDs from CI; will append them if/when observed.","created_at":"2026-01-14T08:39:04Z"},{"id":96,"issue_id":"ge-2b0","author":"rgardler","text":"* remote origin\n Fetch URL: git@github.com:TheWizardsCode/GEngine.git\n Push URL: git@github.com:TheWizardsCode/GEngine.git\n HEAD branch: main\n Remote branches:\n copilot/add-designer-feedback-tooling tracked\n copilot/add-designer-tools-workflows tracked\n copilot/add-rag-pipeline-echoes-llm tracked\n copilot/add-result-aggregation-storage tracked\n copilot/add-rule-based-ai-layer tracked\n copilot/adorable-dog tracked\n copilot/applicable-takin tracked\n copilot/chubby-narwhal tracked\n copilot/colossal-pony tracked\n copilot/enable-per-agent-success-modifiers tracked\n copilot/enable-streaming-default-cli-opt-out tracked\n copilot/extraordinary-leopon tracked\n copilot/fix-issue-51-observer-ai tracked\n copilot/fix-observer-ai-issue-51 tracked\n copilot/frequent-moth tracked\n copilot/improve-core-systems-test-coverage tracked\n copilot/integrate-content-pipeline-ci tracked\n copilot/marginal-cougar tracked\n copilot/metropolitan-flamingo tracked\n copilot/optimize-strategy-parameters tracked\n copilot/resulting-meadowlark tracked\n copilot/update-kubernetes-manifests tracked\n delegate-123/add-delegate-convention tracked\n feature/docs-linting-fixes tracked\n feature/ge-hch.1.4-demo-scene tracked\n feature/ge-urs-ignore-artifacts tracked\n ge-2b0/playwright-prs-only tracked\n ge-6a2/telemetry-e2e tracked\n ge-hch-001/update-opencode-assignees tracked\n ge-hch-ge-hch.4/request-patch tracked\n ge-hch.3.2/stable-story tracked\n ge-hch.3.4.7/add-validate-story-ci tracked\n ge-k3p/playwright-ci tracked\n ge-rw4/commit-agent-docs tracked\n main tracked\n patch/ge-hch.3.4.2/rotation-persistence tracked\n Local branches configured for 'git pull':\n delegate-123/add-delegate-convention merges with remote delegate-123/add-delegate-convention\n delegate-command/update-build-md merges with remote delegate-command/update-build-md\n feature/ge-urs-ignore-artifacts merges with remote feature/ge-urs-ignore-artifacts\n ge-2b0/playwright-prs-only merges with remote ge-2b0/playwright-prs-only\n ge-hch-ge-hch.4/request-patch merges with remote ge-hch-ge-hch.4/request-patch\n ge-hch.3.2/stable-story merges with remote ge-hch.3.2/stable-story\n ge-rw4/commit-agent-docs merges with remote ge-rw4/commit-agent-docs\n main merges with remote main\n Local refs configured for 'git push':\n delegate-123/add-delegate-convention pushes to delegate-123/add-delegate-convention (up to date)\n feature/ge-urs-ignore-artifacts pushes to feature/ge-urs-ignore-artifacts (up to date)\n ge-2b0/playwright-prs-only pushes to ge-2b0/playwright-prs-only (up to date)\n ge-hch-ge-hch.4/request-patch pushes to ge-hch-ge-hch.4/request-patch (up to date)\n ge-hch.3.2/stable-story pushes to ge-hch.3.2/stable-story (local out of date)\n ge-rw4/commit-agent-docs pushes to ge-rw4/commit-agent-docs (local out of date)\n main pushes to main (up to date)\n","created_at":"2026-01-14T08:39:27Z"},{"id":113,"issue_id":"ge-2b0","author":"rgardler","text":"Review indicates PR #131 was merged and a nightly workflow (playwright-nightly.yml) added. Verified playwright.yml triggers are now pull_request and workflow_dispatch (no push-to-main). Closing this bead as completed. -- Actor: Build","created_at":"2026-01-14T09:32:48Z"}]} @@ -15,6 +15,8 @@ {"id":"ge-63c","title":"Full Graph Reachability Checker","description":"BFS/DFS return-path analysis for comprehensive feasibility checking.\n\n## Context\nDeferred from ge-hch.5.15 (AI Director Implementation). Currently only checks knot existence.\n\n## Player Experience Change\nReturn paths will be validated not just for existence but for reachability. Branches with complex return requirements will be properly evaluated.\n\n## Acceptance Criteria\n- [ ] Build knot graph from story structure\n- [ ] BFS/DFS from current scene to return_path\n- [ ] Compute distance and compare to return window\n- [ ] Return confidence based on path complexity\n\n## Dependencies\n- ge-hch.5.15 completion","status":"open","priority":3,"issue_type":"feature","created_at":"2026-01-16T15:04:58.248699256-08:00","created_by":"rgardler","updated_at":"2026-01-16T15:04:58.248699256-08:00","labels":["stage:idea"],"dependencies":[{"issue_id":"ge-63c","depends_on_id":"ge-hch.5.15","type":"discovered-from","created_at":"2026-01-16T15:04:58.250000244-08:00","created_by":"rgardler"}]} {"id":"ge-64j","title":"Update docs: docs/InkJS_README.md","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-05T23:10:10.725093681-08:00","created_by":"rgardler","updated_at":"2026-01-07T02:15:39.971757047-08:00","closed_at":"2026-01-07T02:15:39.971757047-08:00","close_reason":"Closed","dependencies":[{"issue_id":"ge-64j","depends_on_id":"ge-hch.1.2.2","type":"discovered-from","created_at":"2026-01-05T23:10:10.726284101-08:00","created_by":"rgardler"}]} {"id":"ge-6a2","title":"E2E: Assert telemetry & smoke","description":"Extend Playwright E2E tests to assert telemetry events and smoke behaviour.\\n\\nAcceptance Criteria:\\n- Playwright tests assert telemetry events: story_start, choice_selected, smoke_triggered, story_complete.\\n- Tests assert smoke was triggered (via console capture or window.Smoke.getState()).\\n- Tests run and pass locally with npm test.\\n\\nMinimal implementation:\\n- Update tests/demo.smoke.spec.ts or add tests/demo.telemetry.spec.ts to capture console logs and assert telemetry and smoke state.\\n- If needed, expose window.__telemetryEvents in the runner or use Playwright console capture.\\n\\nAssignee: patch\\nDiscovered-from: ge-hch.1.4.2,json","status":"closed","priority":1,"issue_type":"task","assignee":"patch","created_at":"2026-01-06T22:19:59.976931968-08:00","created_by":"rgardler","updated_at":"2026-01-07T00:38:42.931392291-08:00","closed_at":"2026-01-07T00:38:42.931392291-08:00","close_reason":"Completed","dependencies":[{"issue_id":"ge-6a2","depends_on_id":"ge-hch.1.4.2","type":"discovered-from","created_at":"2026-01-06T22:19:59.993082168-08:00","created_by":"rgardler"}],"comments":[{"id":2,"issue_id":"ge-6a2","author":"rgardler","text":"@patch — you're assigned to this task (E2E: Assert telemetry & smoke). Please implement the E2E test changes and open a PR. Concise implementation plan and acceptance checklist below.\\n\\nGoal\\n- Extend Playwright E2E tests so they assert runtime telemetry events and that the smoke effect is triggered.\\n\\nAcceptance criteria (must pass locally and in PR):\\n- Playwright tests assert the telemetry events: , , , and . Capture via console or (preferred) by reading an exposed array.\\n- At least one test asserts the smoke effect was triggered (either by detecting in telemetry or by asserting or equivalent).\\n- Tests run locally with \nadded 103 packages, and audited 104 packages in 5s\n\n20 packages are looking for funding\n run `npm fund` for details\n\nfound 0 vulnerabilities, Downloading Firefox 144.0.2 (playwright build v1497)\u001b[2m from https://cdn.playwright.dev/dbazure/download/playwright/builds/firefox/1497/firefox-ubuntu-24.04-arm64.zip\u001b[22m\n| | 0% of 89.8 MiB\n|■■■■■■■■ | 10% of 89.8 MiB\n|■■■■■■■■■■■■■■■■ | 20% of 89.8 MiB\n|■■■■■■■■■■■■■■■■■■■■■■■■ | 30% of 89.8 MiB\n|■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ | 40% of 89.8 MiB\n|■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ | 50% of 89.8 MiB\n|■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ | 60% of 89.8 MiB\n|■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ | 70% of 89.8 MiB\n|■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ | 80% of 89.8 MiB\n|■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ | 90% of 89.8 MiB\n|■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■| 100% of 89.8 MiB\nFirefox 144.0.2 (playwright build v1497) downloaded to /home/rgardler/.cache/ms-playwright/firefox-1497\nDownloading Webkit 26.0 (playwright build v2227)\u001b[2m from https://cdn.playwright.dev/dbazure/download/playwright/builds/webkit/2227/webkit-ubuntu-24.04-arm64.zip\u001b[22m\n| | 0% of 89.2 MiB\n|■■■■■■■■ | 10% of 89.2 MiB\n|■■■■■■■■■■■■■■■■ | 20% of 89.2 MiB\n|■■■■■■■■■■■■■■■■■■■■■■■■ | 30% of 89.2 MiB\n|■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ | 40% of 89.2 MiB\n|■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ | 50% of 89.2 MiB\n|■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ | 60% of 89.2 MiB\n|■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ | 70% of 89.2 MiB\n|■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ | 80% of 89.2 MiB\n|■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ | 90% of 89.2 MiB\n|■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■| 100% of 89.2 MiB\nWebkit 26.0 (playwright build v2227) downloaded to /home/rgardler/.cache/ms-playwright/webkit-2227, then \n> gengine-demo@0.1.0 test\n> npm run test:demo\n\n\n> gengine-demo@0.1.0 test:demo\n> start-server-and-test \"npm run serve-demo -- --port 4173\" http://127.0.0.1:4173/demo \"playwright test --config=playwright.config.ts\"\n\n1: starting server using command \"npm run serve-demo -- --port 4173\"\nand when url \"[ 'http://127.0.0.1:4173/demo' ]\" is responding with HTTP status code 200\nrunning tests using command \"playwright test --config=playwright.config.ts\"\n\n\n> gengine-demo@0.1.0 serve-demo\n> http-server web --port 4173\n\nStarting up http-server, serving web\n\nhttp-server version: 14.1.1\n\nhttp-server settings: \nCORS: disabled\nCache: 3600 seconds\nConnection Timeout: 120 seconds\nDirectory Listings: visible\nAutoIndex: visible\nServe GZIP Files: false\nServe Brotli Files: false\nDefault File Extension: none\n\nAvailable on:\n http://127.0.0.1:4173\n http://10.255.255.254:4173\n http://192.168.188.207:4173\nHit CTRL-C to stop the server\n\n[2026-01-07T06:23:08.183Z] \"HEAD /demo\" \"axios/1.13.2\"\n[2026-01-07T06:23:08.229Z] \"HEAD /demo/\" \"axios/1.13.2\"\n\nRunning 8 tests using 2 workers\n\n[2026-01-07T06:23:09.615Z] \"GET /demo/\" \"Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Mobile Safari/537.36\"\n[2026-01-07T06:23:09.637Z] \"GET /demo/\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Safari/537.36\"\n[2026-01-07T06:23:09.648Z] \"GET /demo/vendor/ink.js\" \"Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Mobile Safari/537.36\"\n[2026-01-07T06:23:09.648Z] \"GET /demo/js/smoke.js\" \"Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Mobile Safari/537.36\"\n[2026-01-07T06:23:09.664Z] \"GET /demo/js/inkrunner.js\" \"Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Mobile Safari/537.36\"\n[2026-01-07T06:23:09.672Z] \"GET /demo/vendor/ink.js\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Safari/537.36\"\n[2026-01-07T06:23:09.672Z] \"GET /demo/js/smoke.js\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Safari/537.36\"\n[2026-01-07T06:23:09.676Z] \"GET /demo/js/inkrunner.js\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Safari/537.36\"\n ✓ 1 [chromium-desktop] › tests/demo.smoke.spec.ts:38:5 › demo loads and presents initial UI (click) (587ms)\n[2026-01-07T06:23:10.144Z] \"GET /demo/\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Safari/537.36\"\n[2026-01-07T06:23:10.155Z] \"GET /demo/vendor/ink.js\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Safari/537.36\"\n[2026-01-07T06:23:10.156Z] \"GET /demo/js/smoke.js\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Safari/537.36\"\n[2026-01-07T06:23:10.156Z] \"GET /demo/js/inkrunner.js\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Safari/537.36\"\n ✓ 3 [chromium-desktop] › tests/demo.smoke.spec.ts:49:5 › choice can be selected via keyboard (441ms)\n - 4 [chromium-desktop] › tests/demo.smoke.spec.ts:61:5 › choice can be selected via tap (touch)\n[2026-01-07T06:23:10.784Z] \"GET /demo/\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Safari/537.36\"\n[2026-01-07T06:23:10.800Z] \"GET /demo/vendor/ink.js\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Safari/537.36\"\n[2026-01-07T06:23:10.800Z] \"GET /demo/js/smoke.js\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Safari/537.36\"\n[2026-01-07T06:23:10.800Z] \"GET /demo/js/inkrunner.js\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Safari/537.36\"\n ✓ 5 [chromium-desktop] › tests/demo.smoke.spec.ts:73:5 › choice can be selected via controller (Space key surrogate) (421ms)\n ✓ 2 [chromium-touch] › tests/demo.smoke.spec.ts:38:5 › demo loads and presents initial UI (click) (2.1s)\n[2026-01-07T06:23:11.668Z] \"GET /demo/\" \"Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Mobile Safari/537.36\"\n[2026-01-07T06:23:11.688Z] \"GET /demo/vendor/ink.js\" \"Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Mobile Safari/537.36\"\n[2026-01-07T06:23:11.689Z] \"GET /demo/js/smoke.js\" \"Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Mobile Safari/537.36\"\n[2026-01-07T06:23:11.689Z] \"GET /demo/js/inkrunner.js\" \"Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Mobile Safari/537.36\"\n ✓ 6 [chromium-touch] › tests/demo.smoke.spec.ts:49:5 › choice can be selected via keyboard (1.4s)\n[2026-01-07T06:23:13.037Z] \"GET /demo/\" \"Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Mobile Safari/537.36\"\n[2026-01-07T06:23:13.048Z] \"GET /demo/vendor/ink.js\" \"Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Mobile Safari/537.36\"\n[2026-01-07T06:23:13.049Z] \"GET /demo/js/smoke.js\" \"Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Mobile Safari/537.36\"\n[2026-01-07T06:23:13.051Z] \"GET /demo/js/inkrunner.js\" \"Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Mobile Safari/537.36\"\n ✓ 7 [chromium-touch] › tests/demo.smoke.spec.ts:61:5 › choice can be selected via tap (touch) (1.3s)\n[2026-01-07T06:23:14.383Z] \"GET /demo/\" \"Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Mobile Safari/537.36\"\n[2026-01-07T06:23:14.395Z] \"GET /demo/vendor/ink.js\" \"Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Mobile Safari/537.36\"\n[2026-01-07T06:23:14.396Z] \"GET /demo/js/smoke.js\" \"Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Mobile Safari/537.36\"\n[2026-01-07T06:23:14.396Z] \"GET /demo/js/inkrunner.js\" \"Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Mobile Safari/537.36\"\n ✓ 8 [chromium-touch] › tests/demo.smoke.spec.ts:73:5 › choice can be selected via controller (Space key surrogate) (1.1s)\n\n 1 skipped\n 7 passed (6.7s)\nhttp-server stopped..\\n- Include a short bd comment on parent ge-hch.1.4.2 listing changed files and rationale.\\n\\nFiles to modify / create (suggested)\\n- Update: tests/demo.smoke.spec.ts OR create new: tests/demo.telemetry.spec.ts (Playwright test).\\n- Optionally minor runtime hook: small addition to web/demo/js/inkrunner.js to push telemetry into (only if you need it; otherwise capture console logs in Playwright).\\n- No CI changes required in this task, but ensure tests are runnable via existing \n> gengine-demo@0.1.0 test\n> npm run test:demo\n\n\n> gengine-demo@0.1.0 test:demo\n> start-server-and-test \"npm run serve-demo -- --port 4173\" http://127.0.0.1:4173/demo \"playwright test --config=playwright.config.ts\"\n\n1: starting server using command \"npm run serve-demo -- --port 4173\"\nand when url \"[ 'http://127.0.0.1:4173/demo' ]\" is responding with HTTP status code 200\nrunning tests using command \"playwright test --config=playwright.config.ts\"\n\n\n> gengine-demo@0.1.0 serve-demo\n> http-server web --port 4173\n\nStarting up http-server, serving web\n\nhttp-server version: 14.1.1\n\nhttp-server settings: \nCORS: disabled\nCache: 3600 seconds\nConnection Timeout: 120 seconds\nDirectory Listings: visible\nAutoIndex: visible\nServe GZIP Files: false\nServe Brotli Files: false\nDefault File Extension: none\n\nAvailable on:\n http://127.0.0.1:4173\n http://10.255.255.254:4173\n http://192.168.188.207:4173\nHit CTRL-C to stop the server\n\n[2026-01-07T06:23:18.088Z] \"HEAD /demo\" \"axios/1.13.2\"\n[2026-01-07T06:23:18.106Z] \"HEAD /demo/\" \"axios/1.13.2\"\n\nRunning 8 tests using 2 workers\n\n[2026-01-07T06:23:19.354Z] \"GET /demo/\" \"Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Mobile Safari/537.36\"\n[2026-01-07T06:23:19.359Z] \"GET /demo/\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Safari/537.36\"\n[2026-01-07T06:23:19.383Z] \"GET /demo/vendor/ink.js\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Safari/537.36\"\n[2026-01-07T06:23:19.384Z] \"GET /demo/js/smoke.js\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Safari/537.36\"\n[2026-01-07T06:23:19.384Z] \"GET /demo/js/inkrunner.js\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Safari/537.36\"\n[2026-01-07T06:23:19.388Z] \"GET /demo/vendor/ink.js\" \"Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Mobile Safari/537.36\"\n[2026-01-07T06:23:19.389Z] \"GET /demo/js/smoke.js\" \"Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Mobile Safari/537.36\"\n[2026-01-07T06:23:19.393Z] \"GET /demo/js/inkrunner.js\" \"Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Mobile Safari/537.36\"\n ✓ 2 [chromium-desktop] › tests/demo.smoke.spec.ts:38:5 › demo loads and presents initial UI (click) (429ms)\n[2026-01-07T06:23:19.786Z] \"GET /demo/\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Safari/537.36\"\n[2026-01-07T06:23:19.805Z] \"GET /demo/vendor/ink.js\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Safari/537.36\"\n[2026-01-07T06:23:19.805Z] \"GET /demo/js/smoke.js\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Safari/537.36\"\n[2026-01-07T06:23:19.805Z] \"GET /demo/js/inkrunner.js\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Safari/537.36\"\n ✓ 3 [chromium-desktop] › tests/demo.smoke.spec.ts:49:5 › choice can be selected via keyboard (362ms)\n - 4 [chromium-desktop] › tests/demo.smoke.spec.ts:61:5 › choice can be selected via tap (touch)\n[2026-01-07T06:23:20.370Z] \"GET /demo/\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Safari/537.36\"\n[2026-01-07T06:23:20.386Z] \"GET /demo/vendor/ink.js\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Safari/537.36\"\n[2026-01-07T06:23:20.393Z] \"GET /demo/js/smoke.js\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Safari/537.36\"\n[2026-01-07T06:23:20.393Z] \"GET /demo/js/inkrunner.js\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Safari/537.36\"\n ✓ 5 [chromium-desktop] › tests/demo.smoke.spec.ts:73:5 › choice can be selected via controller (Space key surrogate) (425ms)\n ✓ 1 [chromium-touch] › tests/demo.smoke.spec.ts:38:5 › demo loads and presents initial UI (click) (1.7s)\n[2026-01-07T06:23:21.051Z] \"GET /demo/\" \"Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Mobile Safari/537.36\"\n[2026-01-07T06:23:21.063Z] \"GET /demo/vendor/ink.js\" \"Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Mobile Safari/537.36\"\n[2026-01-07T06:23:21.063Z] \"GET /demo/js/smoke.js\" \"Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Mobile Safari/537.36\"\n[2026-01-07T06:23:21.064Z] \"GET /demo/js/inkrunner.js\" \"Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Mobile Safari/537.36\"\n ✓ 6 [chromium-touch] › tests/demo.smoke.spec.ts:49:5 › choice can be selected via keyboard (1.1s)\n[2026-01-07T06:23:22.168Z] \"GET /demo/\" \"Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Mobile Safari/537.36\"\n[2026-01-07T06:23:22.179Z] \"GET /demo/vendor/ink.js\" \"Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Mobile Safari/537.36\"\n[2026-01-07T06:23:22.181Z] \"GET /demo/js/smoke.js\" \"Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Mobile Safari/537.36\"\n[2026-01-07T06:23:22.182Z] \"GET /demo/js/inkrunner.js\" \"Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Mobile Safari/537.36\"\n ✓ 7 [chromium-touch] › tests/demo.smoke.spec.ts:61:5 › choice can be selected via tap (touch) (1.5s)\n[2026-01-07T06:23:23.630Z] \"GET /demo/\" \"Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Mobile Safari/537.36\"\n[2026-01-07T06:23:23.645Z] \"GET /demo/vendor/ink.js\" \"Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Mobile Safari/537.36\"\n[2026-01-07T06:23:23.646Z] \"GET /demo/js/smoke.js\" \"Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Mobile Safari/537.36\"\n[2026-01-07T06:23:23.647Z] \"GET /demo/js/inkrunner.js\" \"Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.4 Mobile Safari/537.36\"\n ✓ 8 [chromium-touch] › tests/demo.smoke.spec.ts:73:5 › choice can be selected via controller (Space key surrogate) (2.1s)\n\n 1 skipped\n 7 passed (7.1s)\nhttp-server stopped. script.\\n\\nSuggested Playwright approach (high level)\\n1. At test start, add OR \\n2. Load demo () and assert initial UI visible.\\n3. Assert or contains 'story_start'.\\n4. Interact with first choice (click/keyboard) and assert 'choice_selected' appears.\\n5. Wait for the line with to display and assert 'smoke_triggered' appears or assert is truthy.\\n6. Drive to story end and assert 'story_complete' is emitted.\\n\\nWhat I need from you when you finish\\n- Open a PR with the test changes. In the PR description include the command(s) you used to verify tests locally and the test results.\\n- Add a bd comment to ge-hch.1.4.2 listing the files you added/modified (paths) and a 1–2 line rationale.\\n- Close this task (ge-6a2) when merged and CI is green.\\n\\nIf you prefer I can draft the exact Playwright test snippet to paste into the repo — say the word and I'll produce it for review.","created_at":"2026-01-07T06:23:25Z"}]} +{"id":"ge-6on","title":"Child","description":"escription","status":"tombstone","priority":2,"issue_type":"task","owner":"ross@gardler.org","created_at":"2026-01-19T18:37:53.395934551-08:00","created_by":"Ross Gardler","updated_at":"2026-01-19T18:38:19.727539615-08:00","deleted_at":"2026-01-19T18:38:19.727539615-08:00","deleted_by":"daemon","delete_reason":"delete","original_type":"task"} +{"id":"ge-7fj","title":"Child","description":"escription","status":"tombstone","priority":2,"issue_type":"task","owner":"ross@gardler.org","created_at":"2026-01-19T18:38:38.156795515-08:00","created_by":"Ross Gardler","updated_at":"2026-01-19T18:41:30.505109921-08:00","deleted_at":"2026-01-19T18:41:30.505109921-08:00","deleted_by":"batch delete","delete_reason":"batch delete","original_type":"task"} {"id":"ge-7si","title":"LORE Adherence Scorer","description":"Detect fact contradictions between AI branches and established LORE.\n\n## Context\nDeferred from ge-hch.5.15 (AI Director Implementation). Currently a placeholder returning 0.3.\n\n## Player Experience Change\nAI branches will never contradict established facts (e.g., character names, world rules). Players won't experience immersion-breaking inconsistencies.\n\n## Acceptance Criteria\n- [ ] Extract facts asserted in branch content\n- [ ] Compare against curated LORE facts\n- [ ] Detect contradictions via embedding similarity\n- [ ] Return risk score based on contradiction severity\n\n## Dependencies\n- ge-hch.5.15.4 (Embedding Service)\n- ge-hch.5.15 completion","status":"open","priority":3,"issue_type":"feature","created_at":"2026-01-16T15:04:58.174378379-08:00","created_by":"rgardler","updated_at":"2026-01-16T15:04:58.174378379-08:00","labels":["stage:idea"],"dependencies":[{"issue_id":"ge-7si","depends_on_id":"ge-hch.5.15","type":"discovered-from","created_at":"2026-01-16T15:04:58.175177909-08:00","created_by":"rgardler"}]} {"id":"ge-7tg","title":"Remove playwright job from pr-ci.yml — prevent duplicate Playwright PR runs","description":"Summary:\\n\\nRemove the 'playwright' job from .github/workflows/pr-ci.yml so Playwright tests on PRs are run only by .github/workflows/playwright.yml (canonical Playwright runner). This prevents duplicate Playwright runs on pull requests.\\n\\nAcceptance criteria (definition of done):\\n- Only one Playwright test run appears per PR (the run from .github/workflows/playwright.yml).\\n- Playwright artifacts (reports, junit, etc.) are uploaded and accessible after the change.\\n- No required checks are unintentionally removed from the branch protection rules; confirm repo required checks still include the Playwright run or equivalent.\\n- A short note is added to the bd issue summarizing verification steps and PR URL.\\n\\nSuggested implementation steps for assignee (Ship):\\n1) Create a branch named: ge-02n/remove-playwright-job (follow repo branch naming rules).\\n2) Edit .github/workflows/pr-ci.yml: remove the entire 'playwright' job block (job key 'playwright' starting at the second job definition). Ensure any artifact upload/download steps remain consistent with other workflows if needed.\\n3) Run a local lint/check for YAML syntax.\\n4) Open a PR from the branch; ensure the Playwright workflow (playwright.yml) runs and pr-ci.yml no longer triggers Playwright.\\n5) Post verification: add a bd comment with the PR URL and results of verification steps.\\n\\nFiles to change:\\n- .github/workflows/pr-ci.yml (remove 'playwright' job),--json:false}","status":"closed","priority":1,"issue_type":"task","assignee":"@Ship","created_at":"2026-01-14T20:06:09.743106343-08:00","created_by":"rgardler","updated_at":"2026-01-14T20:52:15.250729937-08:00","closed_at":"2026-01-14T20:52:15.250734763-08:00","dependencies":[{"issue_id":"ge-7tg","depends_on_id":"ge-02n","type":"discovered-from","created_at":"2026-01-14T20:06:09.776504747-08:00","created_by":"rgardler"}],"comments":[{"id":127,"issue_id":"ge-7tg","author":"rgardler","text":"Started work: created branch ge-02n/remove-playwright-job, removed 'playwright' job from .github/workflows/pr-ci.yml, validated YAML parse locally, and opened PR. See PR URL after creation. Linked to investigation bead ge-02n.","created_at":"2026-01-15T04:09:44Z"},{"id":129,"issue_id":"ge-7tg","author":"rgardler","text":"Cleanup: PR #138 merged; verified origin/main is up-to-date. Checked ancestry: branch 'ge-02n/remove-playwright-job' is NOT an ancestor of origin/main, so it was not merged from this local branch (likely merged from a different branch or fork). I did NOT delete the branch. Leaving 'ge-02n/remove-playwright-job' intact to avoid removing unmerged work. If you want it deleted anyway, please confirm and I'll remove both local and remote branches. Commands run: 'git fetch origin --prune', 'git checkout main', 'git pull --rebase', 'git merge-base --is-ancestor ge-02n/remove-playwright-job origin/main' (result: NOT merged).","created_at":"2026-01-15T04:37:25Z"},{"id":131,"issue_id":"ge-7tg","author":"rgardler","text":"Created rebased copy of branch ge-02n/remove-playwright-job as ge-02n/rebased/remove-playwright-job. Steps performed: fetched origin, backed up original branch to ge-02n/remove-playwright-job.backup, rebased onto origin/main, committed bd export, and pushed new branch. Rebase succeeded with no conflicts. Remote branch: origin/ge-02n/rebased/remove-playwright-job\\n\\nRecommended next step: open a PR from ge-02n/rebased/remove-playwright-job to main for review/merge.\\n\\nRebase result: commits on rebased branch (vs origin/main):\\n- c1e64a0 chore(bd): export bd sync for ge-02n rebased branch\\n- c07f5f7 chore: bd updates — close duplicate-playwright investigation (ge-02n)\\n- 567a057 bd sync: 2026-01-14 20:09:45\\n- dee5230 ci: remove Playwright job from pr-ci.yml (use playwright.yml\\n\\nBranch URL: https://github.com/TheWizardsCode/GEngine/tree/ge-02n/rebased/remove-playwright-job","created_at":"2026-01-15T04:46:01Z"},{"id":133,"issue_id":"ge-7tg","author":"rgardler","text":"Deleted local backup branch ge-02n/remove-playwright-job.backup per user request. Backup branch removed locally; original and rebased branches remain available.","created_at":"2026-01-15T04:49:44Z"},{"id":135,"issue_id":"ge-7tg","author":"rgardler","text":"PR #139 merged; deleted remote and local rebased branch ge-02n/rebased/remove-playwright-job. Final cleanup complete.","created_at":"2026-01-15T04:51:02Z"},{"id":138,"issue_id":"ge-7tg","author":"rgardler","text":"Final: implementation complete and cleanup finished. PRs #138 and #139 merged; duplicate Playwright job removed and branches deleted. Closing implementation bead.","created_at":"2026-01-15T04:52:15Z"}]} {"id":"ge-9bu","title":"Formalize /delegate handoff template and automation","status":"closed","priority":2,"issue_type":"chore","created_at":"2026-01-12T18:40:52.118694982-08:00","created_by":"rgardler","updated_at":"2026-01-12T18:44:15.93263156-08:00","closed_at":"2026-01-12T18:44:15.93263156-08:00","close_reason":"Closed","comments":[{"id":69,"issue_id":"ge-9bu","author":"rgardler","text":"Rationale: Standardize /delegate handoff convention across agent docs so handoffs are explicit, auditable, and aligned with docs/dev/team.md.\n\nFiles edited:\n- .opencode/agent/build.md\n- .opencode/agent/ship.md\n- .opencode/agent/pixel.md\n- .opencode/agent/patch.md\n- .opencode/agent/forge.md\n- .opencode/agent/muse.md\n- .opencode/agent/scribbler.md\n- .opencode/agent/beta.md\n- .opencode/agent/probe.md\n\nRelated PR: https://github.com/TheWizardsCode/GEngine/pull/123 (merged)\n\nCommands run (high level):\n- git checkout -b delegate-123/add-delegate-convention && git rebase origin/main\n- Applied edits to agent docs with edit tool\n- git add .opencode/agent/*.md && git commit -m \"agents: add /delegate handoff convention across agent docs (consistent wording, least-privilege guidance)\"\n- git push -u origin delegate-123/add-delegate-convention\n- gh pr create (PR #123)\n- Switched to main and rebased with origin/main; bd sync completed\n\nNext steps / follow-ups:\n- Add a bd template for /delegate entries and automation to validate them (created chore ge-9bu).\n- Confirm docs/dev/team.md call-signs align with agent files; update only with Producer approval.\n\nActor: Build\n","created_at":"2026-01-13T02:41:10Z"}]} @@ -40,9 +42,11 @@ {"id":"ge-a4h.8","title":"rm Unity refs: ge-hch.1.2.5 (Test Case: Editor loads M0 scene)","description":"Replace Editor load test with local browser Play test loading M0 demo using InkJS wrapper.\\n\\nAcceptance Criteria:\\n- New browser E2E equivalent test described for InkJS (e.g., load demo in headless browser or test harness).\\n","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-05T21:33:34.788629031-08:00","created_by":"rgardler","updated_at":"2026-01-06T22:00:24.773965273-08:00","closed_at":"2026-01-05T22:40:31.413769349-08:00","dependencies":[{"issue_id":"ge-a4h.8","depends_on_id":"ge-a4h","type":"parent-child","created_at":"2026-01-05T21:33:34.798001031-08:00","created_by":"rgardler"},{"issue_id":"ge-a4h.8","depends_on_id":"ge-hch.1.2.5","type":"discovered-from","created_at":"2026-01-05T21:33:34.800682391-08:00","created_by":"rgardler"}]} {"id":"ge-a4h.9","title":"rm Unity refs: ge-hch.1.2.6 (Test Case: Editor mouse advances UI)","description":"Replace browser E2E mouse input test with browser automation test (e.g., Playwright) that clicks advance and asserts state change.\\n\\nAcceptance Criteria:\\n- Test case ported to browser automation.\\n","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-05T21:33:36.964205401-08:00","created_by":"rgardler","updated_at":"2026-01-06T22:00:24.8228538-08:00","closed_at":"2026-01-05T22:40:31.464460429-08:00","dependencies":[{"issue_id":"ge-a4h.9","depends_on_id":"ge-a4h","type":"parent-child","created_at":"2026-01-05T21:33:36.974222441-08:00","created_by":"rgardler"},{"issue_id":"ge-a4h.9","depends_on_id":"ge-hch.1.2.6","type":"discovered-from","created_at":"2026-01-05T21:33:36.977106971-08:00","created_by":"rgardler"}]} {"id":"ge-am0","title":"Implement: smoke visual + Ink trigger","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-05T23:10:10.626603861-08:00","created_by":"rgardler","updated_at":"2026-01-07T02:15:39.937816294-08:00","closed_at":"2026-01-07T02:15:39.937816294-08:00","close_reason":"Closed","dependencies":[{"issue_id":"ge-am0","depends_on_id":"ge-hch.1.2.2","type":"discovered-from","created_at":"2026-01-05T23:10:10.627873481-08:00","created_by":"rgardler"}],"comments":[{"id":20,"issue_id":"ge-am0","author":"rgardler","text":"Wrap-up note: session ended with no code edits. Status remains in_progress. Next steps: implement smoke visual + Ink trigger and add minimal telemetry hooks. Follow-up bead created for CI/telemetry handoff.","created_at":"2026-01-07T09:23:49Z"}]} +{"id":"ge-apq","title":"Production hardening","description":"Epic: Production hardening for services and runtime prototypes.\\n\\nPurpose:\\n- Centralize work to move prototypes and dev-only tooling to production-ready standards (persistence, validation, auth, logging, and deployability).\\n\\nAcceptance criteria:\\n- A set of child tasks exist for specific components (telemetry receiver, ingestion services, demo runner).\\n- Each child task includes clear acceptance criteria and a verification plan.\\n- .beads updated with links to created tasks.\\n\\nSuggested files/paths that may be created/edited:\\n- server/telemetry/receiver.js\\- server/telemetry/events.ndjson\\- server/telemetry/README.md\\- server/telemetry/package.json\\- docs/ (runbook for deployment and config)\\n\\nNotes: This epic is an organizational container. Do not close until child tasks are complete.","status":"open","priority":1,"issue_type":"epic","owner":"ross@gardler.org","created_at":"2026-01-19T15:41:03.536130061-08:00","created_by":"Ross Gardler","updated_at":"2026-01-19T15:41:03.536130061-08:00","labels":["stage:idea"],"comments":[{"id":245,"issue_id":"ge-apq","author":"@OpenCode","text":"Created epic to track production hardening work. Child task created: ge-apq.1 (Harden telemetry receiver).","created_at":"2026-01-19T23:41:10Z"},{"id":246,"issue_id":"ge-apq","author":"@OpenCode","text":"Added label: stage:idea to align with project labeling conventions.","created_at":"2026-01-20T00:40:46Z"}]} +{"id":"ge-apq.1","title":"Harden telemetry receiver (production)","description":"Make the telemetry receiver production-ready.\\n\\nAcceptance criteria:\\n- Persist events to SQLite with basic schema and simple migrations.\\n- Add JSON schema validation for incoming events (reject malformed).\\n- Add optional basic auth (token via env var) and config via environment variables.\\n- Add logging and rotation guidance in README.\\n- Provide a local run and verification plan (curl examples, schema check).\\n\\nFiles expected to change:\\n- server/telemetry/receiver.js\\- server/telemetry/README.md\\- server/telemetry/package.json\\- server/telemetry/db/schema.sql (or migrations)\\n\\nNotes: This task is a child of ge-apq (Production hardening).","status":"open","priority":1,"issue_type":"task","owner":"ross@gardler.org","created_at":"2026-01-19T15:41:07.477695451-08:00","created_by":"Ross Gardler","updated_at":"2026-01-19T15:41:07.477695451-08:00","labels":["stage:idea"],"dependencies":[{"issue_id":"ge-apq.1","depends_on_id":"ge-apq","type":"parent-child","created_at":"2026-01-19T18:46:03.070041277-08:00","created_by":"Ross Gardler"}],"comments":[{"id":247,"issue_id":"ge-apq.1","author":"@OpenCode","text":"Added label: stage:idea to align with project labeling conventions.","created_at":"2026-01-20T00:40:46Z"}]} {"id":"ge-ayd","title":"Skip CI when only Markdown changes","description":"Proposal: Add CI guard so markdown-only changes skip heavy jobs. Implement a lightweight gate job (runs first) that checks the diff for any non-*.md changes; if none, mark success and exit, preventing downstream jobs from running. Keep existing workflows otherwise unchanged; no effect when code/assets/config change. Requires Producer approval before editing workflows.","notes":"PR merged: https://github.com/TheWizardsCode/GEngine/pull/104\\nCI guard for markdown-only diffs landed in Playwright workflow. Gate job writes outputs safely and skips tests when only .md files change.\\nValidation: npm test (unit + Playwright demo) previously passed; workflow rerun passed post-fix.","status":"closed","priority":2,"issue_type":"chore","assignee":"rgardler","created_at":"2026-01-07T02:11:58.639937258-08:00","created_by":"rgardler","updated_at":"2026-01-07T23:33:02.345049506-08:00","closed_at":"2026-01-07T23:33:02.345059039-08:00","external_ref":"https://github.com/TheWizardsCode/GEngine/pull/104","labels":["Status: PR Created"]} {"id":"ge-boe","title":"Re-evaluate Phase 4 Scope","description":"Re-evaluate Phase 4 scope after M2 completion.\n\n## Purpose\nAfter M2 (AI-assisted branching) is complete, review the Phase 4 roadmap items and determine which should be prioritized for implementation.\n\n## Phase 4 Items to Evaluate (from PRD)\n- Expand to additional stories and narrative scenarios\n- Add player-facing UX signals (e.g., \"this choice was AI-generated\"; trust/transparency features)\n- Continuous tuning of Director heuristics and Writer prompts based on production telemetry\n\n## Inputs\n- M2 completion status and lessons learned\n- Telemetry analysis from ge-hch.5.21 (Telemetry Analysis & Tuning)\n- Player feedback from soft launch\n- Phase 4 recommendations document from M9\n\n## Outputs\n- Decision on which Phase 4 items to implement\n- New beads created for approved Phase 4 work\n- Updated roadmap if priorities change\n\n## Dependencies\n- Discovered from: ge-hch.5 (M2 — AI-assisted branching integration)\n- Should be evaluated after M2 milestones complete","status":"open","priority":2,"issue_type":"task","assignee":"Build","created_at":"2026-01-16T13:24:15.530137671-08:00","created_by":"rgardler","updated_at":"2026-01-16T13:24:15.530137671-08:00","labels":["stage:idea"],"dependencies":[{"issue_id":"ge-boe","depends_on_id":"ge-hch.5","type":"discovered-from","created_at":"2026-01-16T13:24:15.532652455-08:00","created_by":"rgardler"}]} -{"id":"ge-bvf","title":"As a user I want a clear home page that lists all the available stories so that I can quickly start playing","description":"# Clear Home Page: Stories List\n\nProblem\n- Players landing on the demo don’t have a single, discoverable page that lists available stories and lets them quickly start playing.\n\nUsers\n- New and returning players who want to pick a story and begin quickly\n- Developers and playtesters who need to launch the demo with different story files\n\nSuccess criteria\n- A responsive stories index page is available under `/demo/` that lists available stories with a `Play` button for each\n- Clicking `Play` opens the existing demo runner at `/demo/` with a query parameter specifying the story (e.g. `/demo/?story=/stories/foo.ink`). The runner must continue to work unchanged and read the `story` query parameter to load that story.\n- Story entries show Title and a clear \"AI (experimental)\" badge when applicable (generated stories); the badge is shown only when `generated: true` is present in the manifest.\n- Page includes ARIA labels for accessibility and is mobile responsive; follow demo UI styles and use semantic markup (ul/li, buttons)\n- A simple manifest file `web/stories/manifest.json` drives the list; manifest can mark stories as `generated: true` and include optional `tags`/`description`\n- Playwright smoke test verifies list load, play button operation, ARIA attributes, and that the runner loads the provided story path\n\nConstraints\n- Do not change the canonical `web/stories/demo.ink` runtime path; the runner expects stories under `/stories/`\n- The demo runner UI should remain unchanged; the stories list only navigates to it with the `story` query parameter\n- Respect story size and validation guidance from `docs/InkJS_README.md` for which stories to list\n- Generated stories must be clearly labeled; do not auto-promote experimental stories without explicit `generated: true` flag in manifest\n\nExisting state\n- Demo runner exists at `web/demo/index.html` and accepts story path from its internal `STORY_PATH` mechanism (current code expects `/stories/demo.ink` by default)\n- Story assets live under `web/stories/` (notes mention `web/stories/generated/` in repo history)\n- Related/config work exists: `ge-hch.4.2` (Feature: story-swap CLI & manifest) which intends a manifest/CLI for swapping stories\n\nDesired change\n- Add a new stories index page at `web/demo/stories.html` (or `web/demo/index-stories.html`) served under `/demo/` that reads `web/stories/manifest.json` and renders the list\n- Provide a small client-side script to fetch/parse the manifest and render entries (Title + Play). Play button navigates to `/demo/?story=`.\n- Include a small manifest schema (example below). Manifest must support `title`, `path`, `description?`, `tags?`, `generated?: boolean`.\n\nManifest example (informal)\n{\n \"stories\": [\n { \"title\": \"Demo\", \"path\": \"/stories/demo.ink\", \"generated\": false },\n { \"title\": \"Generated Test\", \"path\": \"/stories/generated/test.ink\", \"generated\": true }\n ]\n}\n\nFormal JSON Schema (added at `web/stories/manifest.schema.json`):\n- Fields: `title` (string), `path` (string, must start with `/stories/` and end with `.ink`), `description` (optional string), `tags` (optional string[]), `generated` (optional boolean, default false).\n- The schema enforces the top-level `stories` array and disallows additional properties.\n\nLikely duplicates / related docs\n- web/demo/index.html — existing demo runner (player)\n- web/stories/demo.ink — canonical demo story\n- docs/InkJS_README.md — serving & story conventions\n- docs/prd/GDD_M2_ai_assisted_branching.md — AI story guidance and labeling\n- docs/dev/m2-design/demo-return-targets.md — return path considerations\n- history/plan_ge-hch.3_agent_story_gen.md — notes referencing `web/stories/generated/`\n\nRelated issues (Beads ids)\n- ge-hch.4.2 (Feature: story-swap CLI & manifest) — related work; manifest/CLI overlap\n- ge-hch.5.19 (Validation Test Corpus & Tuning) — new/large test stories\n- ge-hch.5.20 (Feature-Flagged Release) — release context\n\nRecommended next step\n- NEW PRD at: `docs/prd/stories_home_PRD.md`\n\nSuggested next step (implementation)\n- Create `web/stories/manifest.json` and validate against `web/stories/manifest.schema.json`\n- Add `web/demo/stories.html` + `web/demo/js/stories-index.js` to render the manifest-driven list\n- Add a small Playwright smoke test `tests/playwright/stories-list.spec.ts`\n\nAreas that may need follow-up (placeholders)\n- Naming/location: confirm new page filename and whether to add a header link from existing `index.html`\n- Manifest ownership: decide CI or manual maintenance of `web/stories/manifest.json` (assume manual for initial implementation)\n- Styling: draft a small style guide to match the demo theme\n\nRisks & assumptions\n- Risk: If manifest is maintained manually it can become stale; consider a CI validation step that fails on invalid manifest format (lint/CI check).\n- Risk: Generated stories may contain invalid Ink or large stories that break the runner; assume maintainers will validate generated stories with `node scripts/validate-story.js` before adding to manifest.\n- Assumption: The demo runner will accept the `story` query parameter at runtime or can be minimally updated to read it without changing behavior for existing uses.\n- Assumption: Playwright tests can reuse existing smoke scripts to reduce test maintenance.\n\nFiles likely to be created/edited\n- `web/demo/stories.html` (new index page)\n- `web/demo/js/stories-index.js` (client script to render list)\n- `web/stories/manifest.json` (manifest driving list)\n- `tests/playwright/stories-list.spec.ts` (smoke test)\n- Small CSS additions or responsive tweaks in `web/demo/index.html` or new CSS file\n\nAcceptance tests / Definition of Done\n- Manual: Visit `http://.../demo/stories.html` on desktop and mobile → page lists stories, `Play` opens the demo with selected story and the runner loads that story to completion of a smoke path\n- Automated: Playwright test confirms list present, `Play` navigates to `/demo/?story=...` and the runner loads the specified story (use existing smoke script where applicable)\n- Accessibility: key interactive elements have ARIA attributes and pass basic a11y checks (role, labels). Add minimal axe-core check in the Playwright test if feasible.\n- Manifest validation: `web/stories/manifest.json` validates against `web/stories/manifest.schema.json` in CI or via a small validation script\n\n\nSaved-artifact\n- This draft saved to: `.opencode/tmp/intake-draft-clear-home-page-stories.md`\n\n\n---\n\nFinal headline (1–2 sentences)\n- Add a responsive stories index page at `/demo/` that lists available stories from `web/stories/manifest.json` and lets players open the demo runner with a selected story. Generated (AI) stories are clearly labeled as experimental; the manifest is schema-validated and the page is ARIA-accessible and mobile-responsive.\n\nPlease review and approve this final draft so I can create the Beads issue. If you'd like edits, list them now (filenames, manifest schema, tests, or PRD path).","status":"open","priority":2,"issue_type":"feature","assignee":"Build","created_at":"2026-01-18T13:54:29.692472851-08:00","created_by":"rgardler","updated_at":"2026-01-18T13:54:35.15570014-08:00","labels":["Status: Intake Completed","stage:idea"]} +{"id":"ge-bvf","title":"As a user I want a clear home page that lists all the available stories so that I can quickly start playing","description":"# Clear Home Page: Stories List\n\nProblem\n- Players landing on the demo don’t have a single, discoverable page that lists available stories and lets them quickly start playing.\n\nUsers\n- New and returning players who want to pick a story and begin quickly\n- Developers and playtesters who need to launch the demo with different story files\n\nSuccess criteria\n- A responsive stories index page is available under `/demo/` that lists available stories with a `Play` button for each\n- Clicking `Play` opens the existing demo runner at `/demo/` with a query parameter specifying the story (e.g. `/demo/?story=/stories/foo.ink`). The runner must continue to work unchanged and read the `story` query parameter to load that story.\n- Story entries show Title and a clear \"AI (experimental)\" badge when applicable (generated stories); the badge is shown only when `generated: true` is present in the manifest.\n- Page includes ARIA labels for accessibility and is mobile responsive; follow demo UI styles and use semantic markup (ul/li, buttons)\n- A simple manifest file `web/stories/manifest.json` drives the list; manifest can mark stories as `generated: true` and include optional `tags`/`description`\n- Playwright smoke test verifies list load, play button operation, ARIA attributes, and that the runner loads the provided story path\n\nConstraints\n- Do not change the canonical `web/stories/demo.ink` runtime path; the runner expects stories under `/stories/`\n- The demo runner UI should remain unchanged; the stories list only navigates to it with the `story` query parameter\n- Respect story size and validation guidance from `docs/InkJS_README.md` for which stories to list\n- Generated stories must be clearly labeled; do not auto-promote experimental stories without explicit `generated: true` flag in manifest\n\nExisting state\n- Demo runner exists at `web/demo/index.html` and accepts story path from its internal `STORY_PATH` mechanism (current code expects `/stories/demo.ink` by default)\n- Story assets live under `web/stories/` (notes mention `web/stories/generated/` in repo history)\n- Related/config work exists: `ge-hch.4.2` (Feature: story-swap CLI & manifest) which intends a manifest/CLI for swapping stories\n\nDesired change\n- Add a new stories index page at `web/demo/stories.html` (or `web/demo/index-stories.html`) served under `/demo/` that reads `web/stories/manifest.json` and renders the list\n- Provide a small client-side script to fetch/parse the manifest and render entries (Title + Play). Play button navigates to `/demo/?story=`.\n- Include a small manifest schema (example below). Manifest must support `title`, `path`, `description?`, `tags?`, `generated?: boolean`.\n\nManifest example (informal)\n{\n \"stories\": [\n { \"title\": \"Demo\", \"path\": \"/stories/demo.ink\", \"generated\": false },\n { \"title\": \"Generated Test\", \"path\": \"/stories/generated/test.ink\", \"generated\": true }\n ]\n}\n\nFormal JSON Schema (added at `web/stories/manifest.schema.json`):\n- Fields: `title` (string), `path` (string, must start with `/stories/` and end with `.ink`), `description` (optional string), `tags` (optional string[]), `generated` (optional boolean, default false).\n- The schema enforces the top-level `stories` array and disallows additional properties.\n\nLikely duplicates / related docs\n- web/demo/index.html — existing demo runner (player)\n- web/stories/demo.ink — canonical demo story\n- docs/InkJS_README.md — serving & story conventions\n- docs/prd/GDD_M2_ai_assisted_branching.md — AI story guidance and labeling\n- docs/dev/m2-design/demo-return-targets.md — return path considerations\n- history/plan_ge-hch.3_agent_story_gen.md — notes referencing `web/stories/generated/`\n\nRelated issues (Beads ids)\n- ge-hch.4.2 (Feature: story-swap CLI & manifest) — related work; manifest/CLI overlap\n- ge-hch.5.19 (Validation Test Corpus & Tuning) — new/large test stories\n- ge-hch.5.20 (Feature-Flagged Release) — release context\n\nRecommended next step\n- NEW PRD at: `docs/prd/stories_home_PRD.md`\n\nSuggested next step (implementation)\n- Create `web/stories/manifest.json` and validate against `web/stories/manifest.schema.json`\n- Add `web/demo/stories.html` + `web/demo/js/stories-index.js` to render the manifest-driven list\n- Add a small Playwright smoke test `tests/playwright/stories-list.spec.ts`\n\nAreas that may need follow-up (placeholders)\n- Naming/location: confirm new page filename and whether to add a header link from existing `index.html`\n- Manifest ownership: decide CI or manual maintenance of `web/stories/manifest.json` (assume manual for initial implementation)\n- Styling: draft a small style guide to match the demo theme\n\nRisks & assumptions\n- Risk: If manifest is maintained manually it can become stale; consider a CI validation step that fails on invalid manifest format (lint/CI check).\n- Risk: Generated stories may contain invalid Ink or large stories that break the runner; assume maintainers will validate generated stories with `node scripts/validate-story.js` before adding to manifest.\n- Assumption: The demo runner will accept the `story` query parameter at runtime or can be minimally updated to read it without changing behavior for existing uses.\n- Assumption: Playwright tests can reuse existing smoke scripts to reduce test maintenance.\n\nFiles likely to be created/edited\n- `web/demo/stories.html` (new index page)\n- `web/demo/js/stories-index.js` (client script to render list)\n- `web/stories/manifest.json` (manifest driving list)\n- `tests/playwright/stories-list.spec.ts` (smoke test)\n- Small CSS additions or responsive tweaks in `web/demo/index.html` or new CSS file\n\nAcceptance tests / Definition of Done\n- Manual: Visit `http://.../demo/stories.html` on desktop and mobile → page lists stories, `Play` opens the demo with selected story and the runner loads that story to completion of a smoke path\n- Automated: Playwright test confirms list present, `Play` navigates to `/demo/?story=...` and the runner loads the specified story (use existing smoke script where applicable)\n- Accessibility: key interactive elements have ARIA attributes and pass basic a11y checks (role, labels). Add minimal axe-core check in the Playwright test if feasible.\n- Manifest validation: `web/stories/manifest.json` validates against `web/stories/manifest.schema.json` in CI or via a small validation script\n\n\nSaved-artifact\n- This draft saved to: `.opencode/tmp/intake-draft-clear-home-page-stories.md`\n\n\n---\n\nFinal headline (1–2 sentences)\n- Add a responsive stories index page at `/demo/` that lists available stories from `web/stories/manifest.json` and lets players open the demo runner with a selected story. Generated (AI) stories are clearly labeled as experimental; the manifest is schema-validated and the page is ARIA-accessible and mobile-responsive.\n\nPlease review and approve this final draft so I can create the Beads issue. If you'd like edits, list them now (filenames, manifest schema, tests, or PRD path).","status":"open","priority":2,"issue_type":"feature","assignee":"Build","created_at":"2026-01-18T13:54:29.692472851-08:00","created_by":"rgardler","updated_at":"2026-01-18T13:54:35.15570014-08:00","labels":["Status: Intake Completed","stage:idea"],"dependencies":[{"issue_id":"ge-bvf","depends_on_id":"ge-hch.6","type":"parent-child","created_at":"2026-01-19T18:43:04.856559226-08:00","created_by":"Ross Gardler"}]} {"id":"ge-chore","title":"Ongoing Maintence (Chores)","description":"This is a top level epic that is used as an ongoing epic to act as a parent to chores that are identified during development work.","status":"open","priority":2,"issue_type":"epic","owner":"ross@gardler.org","created_at":"2026-01-19T02:50:08.209228003-08:00","created_by":"Ross Gardler","updated_at":"2026-01-19T02:50:08.209228003-08:00","labels":["stage:in_progress"],"dependencies":[{"issue_id":"ge-chore","depends_on_id":"ge-cwu","type":"blocks","created_at":"2026-01-19T02:54:41.244342344-08:00","created_by":"Ross Gardler"}]} {"id":"ge-cwu","title":"Integration: run embedding test in CI (manual trigger)","description":"Add a GitHub Actions workflow to run the real-model embedding integration test on-demand via workflow_dispatch and optionally on a nightly schedule. Use the npm script from the related task. Include cache for node_modules and model artifacts if possible.\\n\\nAcceptance criteria:\\n- .github/workflows/integration-embedding.yml exists and can be triggered manually\\n- Workflow uses \nadded 839 packages, and audited 840 packages in 10s\n\n239 packages are looking for funding\n run `npm fund` for details\n\nfound 0 vulnerabilities and runs \\n- Document workflow in CHANGES or PR notes\\n\\nFiles to be created: .github/workflows/integration-embedding.yml","status":"open","priority":1,"issue_type":"feature","created_at":"2026-01-17T20:47:30.221503844-08:00","created_by":"rgardler","updated_at":"2026-01-17T20:47:30.221503844-08:00","labels":["stage:idea"]} {"id":"ge-e8j","title":"Flaky E2E: telemetry smoke fails intermittently on touch worker","status":"closed","priority":3,"issue_type":"bug","created_at":"2026-01-06T23:32:43.292579156-08:00","created_by":"rgardler","updated_at":"2026-01-06T23:55:10.393828203-08:00","closed_at":"2026-01-06T23:55:10.393828203-08:00","close_reason":"Resolved via test instrumentation/relaxation","comments":[{"id":5,"issue_id":"ge-e8j","author":"rgardler","text":"Observed intermittent failure in Playwright run (chromium-touch): smoke state not running when expected. Local run produced 1 failing test in the touch worker while desktop workers passed.\n\nSuggested next steps:\n- Increase timeout/waiting logic in tests when asserting Smoke.getState() (race between UI and effect start).\n- Capture console logs and Smoke.getState() earlier to help diagnose timing.\n- Run failing test repeatedly in CI matrix or locally to reproduce flakiness.\n\nFiles touched during this session:\n- jest.config.js (created)\n- jest.setup.js (created)\n- tests/unit/inkrunner.test.js (created)\n- tests/demo.telemetry.spec.ts (created)\n- tests/demo.smoke.spec.ts (modified)\n- web/demo/js/inkrunner.js (modified)\n- package.json (modified)\n- package-lock.json (modified)\n- .beads/issues.jsonl (modified)\n\n","created_at":"2026-01-07T07:32:49Z"},{"id":6,"issue_id":"ge-e8j","author":"rgardler","text":"Flake mitigated by telemetry test relaxation and smoke.js event instrumentation. Smoke emits smoke_state events and test now accepts either state or events. Stress runs on chromium-touch (repeat-each=3) now pass. No further action planned.","created_at":"2026-01-07T07:55:10Z"}]} @@ -123,7 +127,7 @@ {"id":"ge-hch.4.4.3","title":"ge-hch.4.4.4: Verify CI runs & collect artifacts","description":"Verify CI runs for PR #135 and nightly workflow; collect run IDs/URLs and confirm artifacts uploaded (test-results/replay/**, playwright-report/**).\\n\\nAcceptance criteria:\\n- Locate workflow runs associated with PR #135 and the most recent playwright-nightly run; capture URLs and run IDs.\\n- Confirm npm run test:golden was executed in those runs and passed; if failed, collect replay logs and attach paths.\\n- Verify artifacts (test-results/replay/**, playwright-report/**) are present for failed runs and note retention settings.\\n- Add a bd comment to ge-hch.4.4 with run links and outcome; close this bead (ge-hch.4.4.4) when done.\\n\\nFiles / outputs expected:\\n- BD comment with run URLs and outcomes\\n- If failures: paths to archived artifacts in the workflow run UI\\n\\nAssignee: ship\\nPriority: 1\\nTimebox: 8h","status":"closed","priority":2,"issue_type":"task","assignee":"@Ship","created_at":"2026-01-14T02:02:36.597842196-08:00","created_by":"rgardler","updated_at":"2026-01-14T19:11:25.5880617-08:00","closed_at":"2026-01-14T19:11:25.5880617-08:00","close_reason":"Findings recorded; artifacts downloaded and validated; recommended CI change created","dependencies":[{"issue_id":"ge-hch.4.4.3","depends_on_id":"ge-hch.4.4","type":"parent-child","created_at":"2026-01-14T02:02:36.599119679-08:00","created_by":"rgardler"}],"comments":[{"id":121,"issue_id":"ge-hch.4.4.3","author":"rgardler","text":"/delegate(to: ship)\n\nHi @ship — handoff for ge-hch.4.4.3: Verify CI runs & collect artifacts (timebox: 8h).\n\nGoal\n- Locate workflow runs for PR #135 and the most recent `playwright-nightly` run, confirm `npm run test:golden` executed, and verify artifacts `test-results/replay/**` and `playwright-report/**` are uploaded and downloadable.\n\nChecklist (acceptance criteria)\n1. Identify workflow runs\n - PR #135 run(s): capture run_id(s) and run URL(s).\n - Most recent `playwright-nightly` run: capture run_id and URL.\n2. Confirm execution\n - For each run, confirm `npm run test:golden` was executed (look for the job step or command in logs) and note pass/fail status.\n3. Verify artifacts\n - Confirm artifacts with names/paths similar to `replay-artifacts-` or `playwright-report-` are present.\n - List artifact names, sizes, and retention-days configured.\n - Download one representative artifact (e.g., playwright-report/index.html or replay log) and verify it opens locally.\n4. If failures\n - For failed runs, list the artifact paths and specific files (e.g., test-results/replay/session-.json, trace.zip, screenshot-*.png).\n5. Report\n - Add a bd comment to the parent bead `ge-hch.4.4` with: run URLs, run IDs, artifact names and short outcome note (pass/fail + artifacts present).\n - Add a bd comment to this bead (`ge-hch.4.4.3`) with the same details and any recommendations (e.g., retention-days change, ensure upload uses `if: always()`).\n6. Close this bead (`ge-hch.4.4.3`) when done and reference the comment(s).\n\nHelpful commands\n- List recent workflow runs (GitHub CLI):\n - gh run list --workflow playwright.yml --limit 20\n - gh run list --workflow playwright-nightly.yml --limit 5\n- View run details:\n - gh run view --log\n- List artifacts via API / gh:\n - gh run artifacts \n - gh run download --name \n\nNotes / tips\n- Ensure artifact upload steps used `if: always()` so artifacts are present on failed runs as well.\n- Check artifact retention settings; if <30 days propose updating workflows to `retention-days: 30` for replay-related artifacts.\n- If artifacts are missing, capture the job logs showing the upload step (or absence) and include that evidence in the bd comment.\n\nTimebox: 8 hours. If this cannot be completed in the timebox, add a bd comment documenting partial findings and open a follow-up bead.\n\nExpected outputs (files / bd updates)\n- BD comment on ge-hch.4.4 with run URLs + artifact list and small outcome summary.\n- BD comment on ge-hch.4.4.3 with full findings and downloads checked.\n- Close ge-hch.4.4.3 when complete.\n\nActor: Build (handoff).","created_at":"2026-01-15T03:02:35Z"},{"id":122,"issue_id":"ge-hch.4.4.3","author":"rgardler","text":"@ship — please pick this up: follow the checklist in history/ge-hch.4.4.3_handoff.md, verify PR #135 and the latest playwright-nightly runs, confirm npm run test:golden executed, verify and download artifacts (test-results/replay/**, playwright-report/**), then add bd comments to ge-hch.4.4 and ge-hch.4.4.3 with run URLs, artifact names, and outcomes. Timebox: 8h. If you can't complete in 8h, post partial findings and open a follow-up bead.","created_at":"2026-01-15T03:04:48Z"},{"id":124,"issue_id":"ge-hch.4.4.3","author":"rgardler","text":"Findings for ge-hch.4.4.3 (Verify CI runs & collect artifacts)\n\nRuns inspected:\n- PR #135 (merge run): 20989816533 - https://github.com/TheWizardsCode/GEngine/actions/runs/20989816533\n- PR #135 (push on main after merge): 20989941312 - https://github.com/TheWizardsCode/GEngine/actions/runs/20989941312\n\nFor run 20989816533 (PR run):\n- Jobs: build-validate (success), playwright (success)\n- Playwright job steps: Checkout, Download build artifact, Setup Node.js, Install dependencies, Install Playwright browsers, Start static server, Run Playwright tests, Upload Playwright HTML report, Upload Playwright junit report\n- Confirmed npm run test:golden executed: Run Playwright tests step completed successfully (Playwright tests include running npm scripts). PR CI workflow uses a Playwright step that runs the test suite including golden-path tests.\n- Artifacts present (via API):\n - demo-web (69995 bytes) expires 2026-04-14T09:53:24Z\n - playwright-html-report (221170 bytes) expires 2026-04-14T09:53:24Z\n - playwright-junit (616 bytes) expires 2026-04-14T09:53:24Z\n- Local download: /tmp/ci-artifacts-20989816533/playwright-html-report/index.html (validated: file exists, size 554,179 bytes, contains tag). Also demo-web extracted.\n\nFor run 20989941312 (push run after merge):\n- Run concluded with failure and no jobs/steps ran (workflow file issue). API shows no artifacts. gh run view indicates \"This run likely failed because of a workflow file issue.\" Logs URL present but log not found.\n\nRecommendations:\n- Ensure upload steps always run (even when Playwright job fails) by adding actions/upload-artifact@v4 with if: always() and retention-days: 30.\n\nSuggested YAML snippet to add to Playwright job (replace current upload step):\n\n- name: Upload Playwright artifacts\n if: always()\n uses: actions/upload-artifact@v4\n with:\n name: playwright-test-results-${{ github.run_id }}\n path: |\n test-results/**\n playwright-report/**\n if-no-files-found: ignore\n retention-days: 30\n\nLocal artifacts validated:\n- /tmp/ci-artifacts-20989816533/playwright-html-report/index.html (renders as HTML; read OK)\n\nNext steps:\n- Fix workflow syntax issue that caused the push-run failures (investigate .github/workflows/playwright.yml around line ~44 per YAML LSP error). I did not modify workflows; recommend a small PR to correct YAML formatting and unify upload step to use if: always() and retention-days: 30.\n\nArtifacts downloaded to /tmp:\n- /tmp/ci-artifacts-20989816533/playwright-html-report/index.html\n- /tmp/ci-artifacts-20989799450/playwright-html-report/index.html\n\nBD updates performed:\n- Comment added to parent bead ge-hch.4.4 (id 123) with summary\n- Added in-progress comment on ge-hch.4.4.3 and will add full findings and close the bead after this note.\n","created_at":"2026-01-15T03:11:23Z"}]} {"id":"ge-hch.4.5","title":"Docs: content-iteration workflow & examples","status":"closed","priority":2,"issue_type":"task","assignee":"scribbler","created_at":"2026-01-13T21:23:41.066830537-08:00","created_by":"rgardler","updated_at":"2026-01-16T02:09:45.901598778-08:00","closed_at":"2026-01-16T02:09:45.901598778-08:00","close_reason":"Auto-close: cleanup per status-skill","dependencies":[{"issue_id":"ge-hch.4.5","depends_on_id":"ge-hch.4","type":"parent-child","created_at":"2026-01-13T21:23:41.067758025-08:00","created_by":"rgardler"}],"comments":[{"id":147,"issue_id":"ge-hch.4.5","author":"rgardler","text":"Please post a short (1-3 step) implementation plan and an estimated timebox for this docs task, and note any blockers or required references. If you're ready to start, please set the issue status to 'in_progress' and reply here. Thanks!","created_at":"2026-01-16T06:21:28Z"},{"id":159,"issue_id":"ge-hch.4.5","author":"rgardler","text":"Auto-closing per status-skill recommendation: no linked branches/PRs and not an epic. If this is incorrect, please reopen or add a comment.","created_at":"2026-01-16T10:09:45Z"}]} {"id":"ge-hch.4.6","title":"Task: sample golden-path scripts & example stories","status":"closed","priority":2,"issue_type":"task","assignee":"patch","created_at":"2026-01-13T21:23:41.11805012-08:00","created_by":"rgardler","updated_at":"2026-01-16T02:09:45.832960704-08:00","closed_at":"2026-01-16T02:09:45.832960704-08:00","close_reason":"Auto-close: cleanup per status-skill","dependencies":[{"issue_id":"ge-hch.4.6","depends_on_id":"ge-hch.4","type":"parent-child","created_at":"2026-01-13T21:23:41.118764732-08:00","created_by":"rgardler"}],"comments":[{"id":148,"issue_id":"ge-hch.4.6","author":"rgardler","text":"Please post a short (1-3 step) implementation plan and an estimated timebox for this task, and note any blockers or story examples needed. If you're ready to start, please set the issue status to 'in_progress' and reply here. Thanks!","created_at":"2026-01-16T06:21:28Z"},{"id":158,"issue_id":"ge-hch.4.6","author":"rgardler","text":"Auto-closing per status-skill recommendation: no linked branches/PRs and not an epic. If this is incorrect, please reopen or add a comment.","created_at":"2026-01-16T10:09:45Z"}]} -{"id":"ge-hch.5","title":"M2 — AI-assisted branching integration","description":"M2 — AI-assisted branching integration\n\nIntegrate AI-assisted branch proposal into the runtime, with guardrails and review flow to prevent incoherent or unsafe branches. Include runtime hooks and a validation path for generated content.\n\n## Success Criteria\n- Runtime can accept AI-proposed branches and integrate them into the active story without fatal errors.\n- Guardrail/validation pipeline prevents unsafe or incoherent branches from reaching the runtime (policy, sanitization, or human-in-loop).\n- At least one story includes AI-generated branches validated by the pipeline.\n\n## Milestones\n\n| # | ID | Title | Player Experience Change |\n|---|-----|-------|-------------------------|\n| 1 | ge-hch.5.13 | Demo Story Extension | Richer story with more scenes and choices |\n| 2 | ge-hch.5.14 | AI Writer Implementation | AI options appear at every choice (may be incoherent) |\n| 3 | ge-hch.5.15 | AI Director Implementation | AI options only when contextually appropriate (coherent) |\n| 4 | ge-hch.5.16 | Runtime Integration & Hooks | Save/load works with branches; graceful failure recovery |\n| 5 | ge-hch.5.17 | Telemetry Implementation | Optional branch history view; data collection begins |\n| 6 | ge-hch.5.18 | Policy & Sanitization Engine | Higher quality, polished AI text; no artifacts |\n| 7 | ge-hch.5.19 | Validation Test Corpus & Tuning | More frequent AI options; better variety; full test story |\n| 8 | ge-hch.5.20 | Feature-Flagged Release | Public access; opt-in/out in settings |\n| 9 | ge-hch.5.21 | Telemetry Analysis & Tuning | Smarter timing; personalized branch offers |\n\n**Related**: ge-boe (Re-evaluate Phase 4 Scope) — discovered from this epic, to be evaluated after M2 completion.\n\n### Milestones: changelog\n- 2026-01-16: Created 9 milestones (ge-hch.5.13 through ge-hch.5.21) with linear dependency chain\n- 2026-01-16: Created ge-boe (Re-evaluate Phase 4 Scope) as sibling bead with discovered-from link\n\n## Design Documents\n\n### PRD\n- docs/prd/GDD_M2_ai_assisted_branching.md\n\n### Core Design Specs (docs/dev/m2-design/)\n- director-algorithm.md — 5-step real-time governance algorithm with risk-scoring and fail-safe\n- policy-ruleset.md — Validation rules across 5 categories with severity levels\n- sanitization-transforms.md — Deterministic content transformation algorithms\n- proposal-lifecycle.md — Multi-stage process from Outline through Terminal states\n\n### AI Writer Design\n- lore-model.md — LORE context schema (player state, game state, narrative context)\n- writer-prompts.md — 4 prompt templates with constraint enforcement\n- writer-examples.md — 5 detailed proposal examples with quality metrics\n- determinism-spec.md — Reproducibility framework via input hashing and LLM seeds\n\n### Runtime & Integration\n- runtime-hooks.md — 5 hook point categories with 12-state integration state machine\n- telemetry-schema.md — 6 event types with 5 observability dashboards\n\n### Ink Language Integration\n- ink-validation-review.md — Validation against Ink capabilities and terminology\n\n### Schema Documentation\n- schema-docs.md — Field-by-field explanation of branch proposal schema\n\n### Quality Assurance\n- consistency-review.md — Cross-document consistency verification\n\n## Schemas (docs/dev/m2-schemas/)\n- branch-proposal.json — JSON Schema for AI-generated branch proposals\n- validation-report.json — Validation pipeline output structure\n\n### Example Proposals (docs/dev/m2-schemas/examples/)\n- example_01_guard_confrontation.json\n- example_02_tavern_meeting.json\n- example_03_forest_passage.json\n- example_04_temple_spirit.json\n- example_05_journal_discovery.json\n- example_06_betrayal_moment.json\n- example_07_rival_encounter.json\n- example_08_artifact_chamber.json\n- example_09_revelation_scene.json\n- example_10_final_choice.json","status":"in_progress","priority":1,"issue_type":"epic","assignee":"@rgardler","created_at":"2026-01-07T17:24:12.344698378-08:00","created_by":"rgardler","updated_at":"2026-01-19T03:11:54.951603418-08:00","labels":["Status: Milestones Defined","Status: PRD Completed","milestone"],"dependencies":[{"issue_id":"ge-hch.5","depends_on_id":"ge-hch.4","type":"blocks","created_at":"2026-01-07T17:24:30.408356193-08:00","created_by":"rgardler"}],"comments":[{"id":176,"issue_id":"ge-hch.5","author":"rgardler","text":"Updated PRD to focus on player runtime experience; added AI Director & AI Writer roles and 'return window' constraint. Draft at docs/prd/GDD_M2_ai_assisted_branching.md","created_at":"2026-01-16T18:02:05Z"},{"id":177,"issue_id":"ge-hch.5","author":"rgardler","text":"Aligned entire PRD body with player-focused problem statement. Expanded Users section to include end-players as primary users; rewrote Requirements to focus on runtime player experience, AI Director governance, AI Writer generation. Updated Quality gates with player experience validation metrics. Expanded Open Questions with player experience and LORE context questions. PRD now comprehensively covers emergent storytelling at runtime.","created_at":"2026-01-16T18:19:41Z"},{"id":178,"issue_id":"ge-hch.5","author":"rgardler","text":"Phase 0 design complete: PRD finalized, schemas defined (branch proposal + validation report), policy ruleset + sanitization transforms documented, AI Director algorithm fully specified. PR #152 ready for stakeholder review. Next: Phase 0.7 for AI Writer design + integration hooks + telemetry schema.","created_at":"2026-01-16T18:29:11Z"},{"id":179,"issue_id":"ge-hch.5","author":"rgardler","text":"Major design improvement: Replaced determinism requirement with adaptive creativity control. Director now dynamically adjusts Writer's creativity (0.0–1.0) based on player engagement, recent success, and narrative phase. Enables fresh, varied proposals while maintaining coherence. Eliminates boring deterministic reproduction.","created_at":"2026-01-16T18:31:39Z"},{"id":180,"issue_id":"ge-hch.5","author":"rgardler","text":"Fixed: Removed residual human-in-loop reference. Rollback is automatic on error; operators cannot manually revert branches. M2 is fully automated at runtime.","created_at":"2026-01-16T18:39:33Z"},{"id":181,"issue_id":"ge-hch.5","author":"rgardler","text":"Fixed: Removed real-time operator monitoring. Telemetry is emitted for post-launch analysis and learning between phases, not for runtime monitoring. M2 is fully automated.","created_at":"2026-01-16T18:40:20Z"},{"id":182,"issue_id":"ge-hch.5","author":"rgardler","text":"Clarity pass: Removed all misleading references to operator/producer runtime involvement. M2 is 100% automated. All human involvement (learning, tuning) happens between phases, not at runtime.","created_at":"2026-01-16T18:40:55Z"},{"id":183,"issue_id":"ge-hch.5","author":"rgardler","text":"Reorganized: Moved M2 design documents from history/ to docs/dev/ for permanent project documentation. Directory structure preserved.","created_at":"2026-01-16T18:44:45Z"},{"id":184,"issue_id":"ge-hch.5","author":"rgardler","text":"Phase 0 design continuation complete. All three remaining subtasks closed:\n\n✅ ge-hch.5.10: AI Writer design (LORE model, prompts, examples, determinism)\n✅ ge-hch.5.11: Runtime integration hooks and rollback semantics \n✅ ge-hch.5.12: Telemetry schema and observability design\n\nComplete M2 design specification now ready for Phase 1 implementation.\n\nFiles created:\n- history/m2-design/lore-model.md (LORE context model for Writer)\n- history/m2-design/writer-prompts.md (Prompt templates with constraint enforcement)\n- history/m2-design/writer-examples.md (5 detailed proposal examples)\n- history/m2-design/determinism-spec.md (Reproducibility and seeding strategy)\n- history/m2-design/runtime-hooks.md (Safe injection points and integration flow)\n- history/m2-design/telemetry-schema.md (Event schema and observability dashboards)\n\nAll files in history/m2-design/ ready for stakeholder review and Phase 1 planning.","created_at":"2026-01-16T18:51:17Z"},{"id":185,"issue_id":"ge-hch.5","author":"rgardler","text":"## Consistency Review Completed (2026-01-16)\n\nCompleted comprehensive cross-document consistency and completeness review of all M2 documentation.\n\n### Documents Reviewed (15 total)\n- PRD, director-algorithm.md, lore-model.md, writer-prompts.md, writer-examples.md\n- determinism-spec.md, sanitization-transforms.md, proposal-lifecycle.md, telemetry-schema.md\n- runtime-hooks.md, policy-ruleset.md, schema-docs.md, ink-validation-review.md\n- branch-proposal.json, validation-report.json\n\n### Fixes Applied\n- **PRD Risk Score**: Fixed metric count from '5 metrics' to '6 metrics' (player_preference_fit was added earlier but PRD wasn't updated)\n\n### Verified Consistent\n- State machine states: 12 (as claimed in PRD)\n- Telemetry event types: 6 (as claimed in PRD)\n- Latency targets: consistent across all docs\n- Terminology: consistent usage throughout\n- Cross-references: all links valid\n\n### Artifacts\n- Created: `docs/dev/m2-design/consistency-review.md`\n- Commit: 44e4859\n\nAll M2 design documentation is now verified consistent and complete.","created_at":"2026-01-16T20:20:06Z"},{"id":190,"issue_id":"ge-hch.5","author":"rgardler","text":"Sub-milestone ge-hch.5.14 (AI Writer Implementation) closed after PR #153 merged; AI options now live in demo with schema/profanity guard. Next focus: ge-hch.5.16.1 WebLLM local mode.","created_at":"2026-01-17T03:42:57Z"}]} +{"id":"ge-hch.5","title":"M2 — AI-assisted branching integration","description":"M2 — AI-assisted branching integration\n\nIntegrate AI-assisted branch proposal into the runtime, with guardrails and review flow to prevent incoherent or unsafe branches. Include runtime hooks and a validation path for generated content.\n\n## Success Criteria\n- Runtime can accept AI-proposed branches and integrate them into the active story without fatal errors.\n- Guardrail/validation pipeline prevents unsafe or incoherent branches from reaching the runtime (policy, sanitization, or human-in-loop).\n- At least one story includes AI-generated branches validated by the pipeline.\n\n## Milestones\n\n| # | ID | Title | Player Experience Change |\n|---|-----|-------|-------------------------|\n| 1 | ge-hch.5.13 | Demo Story Extension | Richer story with more scenes and choices |\n| 2 | ge-hch.5.14 | AI Writer Implementation | AI options appear at every choice (may be incoherent) |\n| 3 | ge-hch.5.15 | AI Director Implementation | AI options only when contextually appropriate (coherent) |\n| 4 | ge-hch.5.16 | Runtime Integration & Hooks | Save/load works with branches; graceful failure recovery |\n| 5 | ge-hch.5.17 | Telemetry Implementation | Optional branch history view; data collection begins |\n| 6 | ge-hch.5.18 | Policy & Sanitization Engine | Higher quality, polished AI text; no artifacts |\n| 7 | ge-hch.5.19 | Validation Test Corpus & Tuning | More frequent AI options; better variety; full test story |\n| 8 | ge-hch.5.20 | Feature-Flagged Release | Public access; opt-in/out in settings |\n| 9 | ge-hch.5.21 | Telemetry Analysis & Tuning | Smarter timing; personalized branch offers |\n\n**Related**: ge-boe (Re-evaluate Phase 4 Scope) — discovered from this epic, to be evaluated after M2 completion.\n\n### Milestones: changelog\n- 2026-01-16: Created 9 milestones (ge-hch.5.13 through ge-hch.5.21) with linear dependency chain\n- 2026-01-16: Created ge-boe (Re-evaluate Phase 4 Scope) as sibling bead with discovered-from link\n\n## Design Documents\n\n### PRD\n- docs/prd/GDD_M2_ai_assisted_branching.md\n\n### Core Design Specs (docs/dev/m2-design/)\n- director-algorithm.md — 5-step real-time governance algorithm with risk-scoring and fail-safe\n- policy-ruleset.md — Validation rules across 5 categories with severity levels\n- sanitization-transforms.md — Deterministic content transformation algorithms\n- proposal-lifecycle.md — Multi-stage process from Outline through Terminal states\n\n### AI Writer Design\n- lore-model.md — LORE context schema (player state, game state, narrative context)\n- writer-prompts.md — 4 prompt templates with constraint enforcement\n- writer-examples.md — 5 detailed proposal examples with quality metrics\n- determinism-spec.md — Reproducibility framework via input hashing and LLM seeds\n\n### Runtime & Integration\n- runtime-hooks.md — 5 hook point categories with 12-state integration state machine\n- telemetry-schema.md — 6 event types with 5 observability dashboards\n\n### Ink Language Integration\n- ink-validation-review.md — Validation against Ink capabilities and terminology\n\n### Schema Documentation\n- schema-docs.md — Field-by-field explanation of branch proposal schema\n\n### Quality Assurance\n- consistency-review.md — Cross-document consistency verification\n\n## Schemas (docs/dev/m2-schemas/)\n- branch-proposal.json — JSON Schema for AI-generated branch proposals\n- validation-report.json — Validation pipeline output structure\n\n### Example Proposals (docs/dev/m2-schemas/examples/)\n- example_01_guard_confrontation.json\n- example_02_tavern_meeting.json\n- example_03_forest_passage.json\n- example_04_temple_spirit.json\n- example_05_journal_discovery.json\n- example_06_betrayal_moment.json\n- example_07_rival_encounter.json\n- example_08_artifact_chamber.json\n- example_09_revelation_scene.json\n- example_10_final_choice.json","status":"in_progress","priority":1,"issue_type":"epic","assignee":"@rgardler","created_at":"2026-01-07T17:24:12.344698378-08:00","created_by":"rgardler","updated_at":"2026-01-19T03:11:54.951603418-08:00","labels":["Status: Milestones Defined","Status: PRD Completed","milestone","stage:in_progress"],"dependencies":[{"issue_id":"ge-hch.5","depends_on_id":"ge-hch.4","type":"blocks","created_at":"2026-01-07T17:24:30.408356193-08:00","created_by":"rgardler"}],"comments":[{"id":176,"issue_id":"ge-hch.5","author":"rgardler","text":"Updated PRD to focus on player runtime experience; added AI Director & AI Writer roles and 'return window' constraint. Draft at docs/prd/GDD_M2_ai_assisted_branching.md","created_at":"2026-01-16T18:02:05Z"},{"id":177,"issue_id":"ge-hch.5","author":"rgardler","text":"Aligned entire PRD body with player-focused problem statement. Expanded Users section to include end-players as primary users; rewrote Requirements to focus on runtime player experience, AI Director governance, AI Writer generation. Updated Quality gates with player experience validation metrics. Expanded Open Questions with player experience and LORE context questions. PRD now comprehensively covers emergent storytelling at runtime.","created_at":"2026-01-16T18:19:41Z"},{"id":178,"issue_id":"ge-hch.5","author":"rgardler","text":"Phase 0 design complete: PRD finalized, schemas defined (branch proposal + validation report), policy ruleset + sanitization transforms documented, AI Director algorithm fully specified. PR #152 ready for stakeholder review. Next: Phase 0.7 for AI Writer design + integration hooks + telemetry schema.","created_at":"2026-01-16T18:29:11Z"},{"id":179,"issue_id":"ge-hch.5","author":"rgardler","text":"Major design improvement: Replaced determinism requirement with adaptive creativity control. Director now dynamically adjusts Writer's creativity (0.0–1.0) based on player engagement, recent success, and narrative phase. Enables fresh, varied proposals while maintaining coherence. Eliminates boring deterministic reproduction.","created_at":"2026-01-16T18:31:39Z"},{"id":180,"issue_id":"ge-hch.5","author":"rgardler","text":"Fixed: Removed residual human-in-loop reference. Rollback is automatic on error; operators cannot manually revert branches. M2 is fully automated at runtime.","created_at":"2026-01-16T18:39:33Z"},{"id":181,"issue_id":"ge-hch.5","author":"rgardler","text":"Fixed: Removed real-time operator monitoring. Telemetry is emitted for post-launch analysis and learning between phases, not for runtime monitoring. M2 is fully automated.","created_at":"2026-01-16T18:40:20Z"},{"id":182,"issue_id":"ge-hch.5","author":"rgardler","text":"Clarity pass: Removed all misleading references to operator/producer runtime involvement. M2 is 100% automated. All human involvement (learning, tuning) happens between phases, not at runtime.","created_at":"2026-01-16T18:40:55Z"},{"id":183,"issue_id":"ge-hch.5","author":"rgardler","text":"Reorganized: Moved M2 design documents from history/ to docs/dev/ for permanent project documentation. Directory structure preserved.","created_at":"2026-01-16T18:44:45Z"},{"id":184,"issue_id":"ge-hch.5","author":"rgardler","text":"Phase 0 design continuation complete. All three remaining subtasks closed:\n\n✅ ge-hch.5.10: AI Writer design (LORE model, prompts, examples, determinism)\n✅ ge-hch.5.11: Runtime integration hooks and rollback semantics \n✅ ge-hch.5.12: Telemetry schema and observability design\n\nComplete M2 design specification now ready for Phase 1 implementation.\n\nFiles created:\n- history/m2-design/lore-model.md (LORE context model for Writer)\n- history/m2-design/writer-prompts.md (Prompt templates with constraint enforcement)\n- history/m2-design/writer-examples.md (5 detailed proposal examples)\n- history/m2-design/determinism-spec.md (Reproducibility and seeding strategy)\n- history/m2-design/runtime-hooks.md (Safe injection points and integration flow)\n- history/m2-design/telemetry-schema.md (Event schema and observability dashboards)\n\nAll files in history/m2-design/ ready for stakeholder review and Phase 1 planning.","created_at":"2026-01-16T18:51:17Z"},{"id":185,"issue_id":"ge-hch.5","author":"rgardler","text":"## Consistency Review Completed (2026-01-16)\n\nCompleted comprehensive cross-document consistency and completeness review of all M2 documentation.\n\n### Documents Reviewed (15 total)\n- PRD, director-algorithm.md, lore-model.md, writer-prompts.md, writer-examples.md\n- determinism-spec.md, sanitization-transforms.md, proposal-lifecycle.md, telemetry-schema.md\n- runtime-hooks.md, policy-ruleset.md, schema-docs.md, ink-validation-review.md\n- branch-proposal.json, validation-report.json\n\n### Fixes Applied\n- **PRD Risk Score**: Fixed metric count from '5 metrics' to '6 metrics' (player_preference_fit was added earlier but PRD wasn't updated)\n\n### Verified Consistent\n- State machine states: 12 (as claimed in PRD)\n- Telemetry event types: 6 (as claimed in PRD)\n- Latency targets: consistent across all docs\n- Terminology: consistent usage throughout\n- Cross-references: all links valid\n\n### Artifacts\n- Created: `docs/dev/m2-design/consistency-review.md`\n- Commit: 44e4859\n\nAll M2 design documentation is now verified consistent and complete.","created_at":"2026-01-16T20:20:06Z"},{"id":190,"issue_id":"ge-hch.5","author":"rgardler","text":"Sub-milestone ge-hch.5.14 (AI Writer Implementation) closed after PR #153 merged; AI options now live in demo with schema/profanity guard. Next focus: ge-hch.5.16.1 WebLLM local mode.","created_at":"2026-01-17T03:42:57Z"}]} {"id":"ge-hch.5.1","title":"Agent: Story Author (Ink)","description":"Define and implement a Story Author agent that generates valid Ink (.ink) stories suitable for runtime execution and automated testing.\\n\\n## Acceptance Criteria\\n- Generates a .ink file that parses with InkJS with no fatal errors.\\n- Includes metadata manifest (title, author, prompt, version).\\n- Emits telemetry tags/Ink markers required by M1 (story_start, choice_selected, smoke_trigger).\\n- Output placed at web/stories/generated/.ink and web/stories/generated/.json.\\n\\n## Minimal Implementation\\n- Agent spec (history/ai/agent-story-author.md).\\n- Test harness that runs the agent, validates parse via InkJS, and runs the golden-path smoke test.\\n\\n## Dependencies\\n- Access to an OpenAI-compatible endpoint (configurable).\\n- inkjs runner & test harness (existing).\\n\\n## Deliverables\\n- history/ai/agent-story-author.md, web/stories/generated/*, tests for validation.\\n","status":"closed","priority":2,"issue_type":"feature","assignee":"Build","created_at":"2026-01-07T19:37:54.162109871-08:00","created_by":"rgardler","updated_at":"2026-01-18T23:14:37.413579174-08:00","closed_at":"2026-01-18T23:14:37.413590874-08:00","dependencies":[{"issue_id":"ge-hch.5.1","depends_on_id":"ge-hch.5","type":"parent-child","created_at":"2026-01-07T19:37:54.16558813-08:00","created_by":"rgardler"},{"issue_id":"ge-hch.5.1","depends_on_id":"ge-hch.3.4","type":"blocks","created_at":"2026-01-07T19:45:42.779141862-08:00","created_by":"rgardler"},{"issue_id":"ge-hch.5.1","depends_on_id":"ge-hch.5.3","type":"blocks","created_at":"2026-01-07T19:46:06.489939062-08:00","created_by":"rgardler"}],"comments":[{"id":172,"issue_id":"ge-hch.5.1","author":"rgardler","text":"Auto-closing per status-skill recommendation: no linked branches/PRs and not an epic. If this is incorrect, please reopen or add a comment.","created_at":"2026-01-16T10:09:47Z"}]} {"id":"ge-hch.5.1.1","title":"Docs: Agent spec (Story Author)","description":"Write agent spec describing prompts, input/output contracts, validation steps, deterministic seed option, and example prompt templates. Place file at history/ai/agent-story-author.md.\\n\\n## Acceptance Criteria\\n- history/ai/agent-story-author.md created and added to repo.\\n- Includes example prompt, manifest schema, and validation steps.\\n","status":"closed","priority":2,"issue_type":"task","assignee":"Scribbler","created_at":"2026-01-07T19:37:56.434034075-08:00","created_by":"rgardler","updated_at":"2026-01-16T02:09:46.991789018-08:00","closed_at":"2026-01-16T02:09:46.991789018-08:00","close_reason":"Auto-close: cleanup per status-skill","dependencies":[{"issue_id":"ge-hch.5.1.1","depends_on_id":"ge-hch.5.1","type":"parent-child","created_at":"2026-01-07T19:37:56.434980367-08:00","created_by":"rgardler"}],"comments":[{"id":26,"issue_id":"ge-hch.5.1.1","author":"rgardler","text":"Agent spec (inlined into bead ge-hch.5.1.1)\n\nPurpose\n- Provide a clear, machine-readable contract for an autonomous Story Author agent that emits valid Ink (.ink) stories plus a companion manifest.\n\nInputs\n- Prompt template(s): supports both Short and Long templates. Prompts should include explicit guardrails (max length, allowed tags, prohibited content).\n- Optional seed: numeric seed for deterministic generation.\n- Config: temperature (default 0.6), max_tokens, model endpoint (OpenAI-compatible URL), provenance fields (author, branch).\n\nOutput contract\n- Primary artifact: web/stories/generated/.ink (Ink file). Requirements:\n - Must begin with a metadata header (Ink comment lines or special tag) containing: title, author, version, seed.\n - Include telemetry tags at logical points: e.g., // @telemetry:story_start, // @telemetry:choice_selected, // @telemetry:smoke_trigger\n - Use clear choice markers so InkJS renders choices normally.\n- Companion manifest JSON: web/stories/generated/.json with schema:\n - { title: string, author: string, prompt: string, seed: number, version: string, safe_rating: string }\n\nValidation steps (agent harness)\n1) Parse run: use InkJS parser/load to ensure no parse errors.\n2) Runtime smoke: load the story in a minimal runner to ensure it reaches first choice and that telemetry tags exist.\n3) Golden-path test: the generated story should complete in a scripted run or at least reach a defined end-state without exceptions (optional for first pass).\n\nDeterminism & seeding\n- Agent must support deterministic mode: given the same prompt + seed + model config, output should be repeatable.\n- The seed value is recorded in manifest.\n\nSafety and guardrails\n- Output must be post-processed to remove content violating safety constraints. Agent must include a sanitization pass and a safety rating in manifest.\n\nExample prompt templates\n- Short template (recommended default):\n Write a short interactive Ink story (~200-400 words) suitable for browser play. Include branching choices (2-3 choices) and insert telemetry markers: // @telemetry:story_start at the start, // @telemetry:choice_selected before each choice, and // @telemetry:smoke_trigger as a tag on a single passage. Output only a single .ink file content.\n\n- Long template (detailed):\n You are an Ink author. Create a 5-8 node interactive story suitable for a 10-15 minute play session. Include: a title, 2-3 branching choices per decision point, an explicit passage marked with // @telemetry:smoke_trigger (include duration=3s and intensity=medium as a comment), and ensure all choices are labeled for machine parsing. Keep language safe for ages 13+. Return only the Ink source and ensure it compiles.\n\nTesting expectations\n- Unit tests validate manifest schema and presence of telemetry tags.\n- E2E tests run validate-story then run the replay harness if provided.\n\nAgent run CLI\n- scripts/generate_story.js --template short|long --seed 1234 --out web/stories/generated\n\nOpen questions\n- Model selection: default to OpenAI-compatible endpoint with online auth. Confirm model families allowed.\n\n","created_at":"2026-01-08T03:53:03Z"},{"id":171,"issue_id":"ge-hch.5.1.1","author":"rgardler","text":"Auto-closing per status-skill recommendation: no linked branches/PRs and not an epic. If this is incorrect, please reopen or add a comment.","created_at":"2026-01-16T10:09:46Z"}]} {"id":"ge-hch.5.1.2","title":"Implement: Story Author harness","description":"Create a harness that runs the Story Author agent, writes output to web/stories/generated/, validates Ink parse with InkJS, and triggers the inkrunner golden-path test.\\n\\n## Acceptance Criteria\\n- Script exists (scripts/generate_story.js or similar).\\n- Generated files placed under web/stories/generated/.\\n- Validation step runs inkjs load and fails on parse/runtime errors.\\n","status":"closed","priority":2,"issue_type":"task","assignee":"Patch","created_at":"2026-01-07T19:37:58.747209456-08:00","created_by":"rgardler","updated_at":"2026-01-16T02:09:46.877694809-08:00","closed_at":"2026-01-16T02:09:46.877694809-08:00","close_reason":"Auto-close: cleanup per status-skill","dependencies":[{"issue_id":"ge-hch.5.1.2","depends_on_id":"ge-hch.5.1","type":"parent-child","created_at":"2026-01-07T19:37:58.748527006-08:00","created_by":"rgardler"},{"issue_id":"ge-hch.5.1.2","depends_on_id":"ge-hch.5.3","type":"blocks","created_at":"2026-01-07T19:45:44.836804565-08:00","created_by":"rgardler"},{"issue_id":"ge-hch.5.1.2","depends_on_id":"ge-hch.3.5","type":"blocks","created_at":"2026-01-07T19:45:47.069170091-08:00","created_by":"rgardler"}],"comments":[{"id":170,"issue_id":"ge-hch.5.1.2","author":"rgardler","text":"Auto-closing per status-skill recommendation: no linked branches/PRs and not an epic. If this is incorrect, please reopen or add a comment.","created_at":"2026-01-16T10:09:46Z"}]} @@ -201,11 +205,13 @@ {"id":"ge-okh","title":"Add npm script + docs to run embedding integration test","description":"Add an npm script to run the real-model embedding integration test (EMBED_NODE=1). Include a short note in web/demo/README.md describing the script and how to run it locally.\\n\\nAcceptance criteria:\\n- package.json has script that runs: \\n- web/demo/README.md contains a 1-2 line note explaining the script and env flags\\n- Tests: running the script locally succeeds (developer responsibility)\\n\\nFiles to be changed: , ","status":"open","priority":2,"issue_type":"task","created_at":"2026-01-17T20:47:17.395948499-08:00","created_by":"rgardler","updated_at":"2026-01-17T20:47:17.395948499-08:00","labels":["stage:idea"]} {"id":"ge-oow","title":"Refactor: remove jq fallback for replay failure JSON","description":"### Goal\\nRemove the -based fallback in that synthesizes failure JSON from logs. The replay runner now writes structured JSON via ; the workflow should rely on that structured output instead of reconstructing it from logs.\\n\\n### Acceptance Criteria\\n- The workflow no longer runs to synthesize .\\n- The workflow copies or uploads the runner-produced (or a runner-produced failure file) into artifacts/results and archives it for failing runs.\\n- A CI run for the PR demonstrates a failing replay produces an uploaded visible in the job artifacts.\\n- Files touched are limited to (and any small adjustments to only if strictly necessary).\\n\\n### Suggested Implementation\\n1. Edit to remove the fallback block and instead rely on produced by the runner.\\n2. Ensure the workflow still copies raw logs and uploads & .\\n3. Run CI on a PR that intentionally fails a replay to confirm artifact presence.\\n\\n### Timebox\\nEstimate: 1-2 hours.\\n\\n### Notes\\n- Keep an eye on edge cases where runner result is missing; if this proves to happen, we may want a minimal guard that reports a clear error but does not attempt to reconstruct the JSON.\\n\\n### Related\\ndiscovered-from:ge-hch.4.3\\n","status":"closed","priority":3,"issue_type":"task","assignee":"rgardler","created_at":"2026-01-16T00:32:00.440882328-08:00","created_by":"rgardler","updated_at":"2026-01-16T01:38:44.850810587-08:00","closed_at":"2026-01-16T01:38:44.850810587-08:00","close_reason":"Completed: removed jq fallback; PR #151 merged","dependencies":[{"issue_id":"ge-oow","depends_on_id":"ge-hch.4.3","type":"discovered-from","created_at":"2026-01-16T00:32:00.453040701-08:00","created_by":"rgardler"}],"comments":[{"id":156,"issue_id":"ge-oow","author":"rgardler","text":"Created branch ge-oow/remove-jq-fallback and opened PR #151 to remove jq fallback; change uses printf to emit minimal failure JSON if runner result is missing. Marking as in_progress and assigned to rgardler.","created_at":"2026-01-16T09:34:53Z"},{"id":157,"issue_id":"ge-oow","author":"rgardler","text":"Merged PR #151: removed jq fallback and emit minimal failure JSON using printf. Verified replay artifacts show no failures for this change. Closing bead.","created_at":"2026-01-16T09:38:43Z"}]} {"id":"ge-osd","title":"Restore original demo story for smoke tests","status":"closed","priority":1,"issue_type":"bug","created_at":"2026-01-06T22:09:37.056596959-08:00","created_by":"rgardler","updated_at":"2026-01-06T22:10:00.371743266-08:00","closed_at":"2026-01-06T22:10:00.371743266-08:00","close_reason":"Done","comments":[{"id":1,"issue_id":"ge-osd","author":"rgardler","text":"Fixed smoke tests broken by demo story changes by adding web/stories/test.ink (pre-903f044 demo story) and routing /stories/demo.ink to that file in Playwright.\n\nChanges:\n- web/stories/test.ink\n- tests/demo.smoke.spec.ts\n\nCommands:\n- npm test","created_at":"2026-01-07T06:09:54Z"}]} +{"id":"ge-qip","title":"Parent: Test parent/child relationship","description":"escription","status":"tombstone","priority":2,"issue_type":"epic","owner":"ross@gardler.org","created_at":"2026-01-19T18:38:38.077369615-08:00","created_by":"Ross Gardler","updated_at":"2026-01-19T18:41:54.055362933-08:00","deleted_at":"2026-01-19T18:41:54.055362933-08:00","deleted_by":"daemon","delete_reason":"delete","original_type":"epic"} {"id":"ge-rw4","title":"Commit: agent docs edits and AGENTS.md","description":"Summary:\\nCommit the current agent docs edits and AGENTS.md into a named branch and create a local commit with the provided message. Do NOT push.\\n\\nFiles to commit (from git status):\\n- .opencode/agent/beta.md (deleted)\\n- .opencode/agent/build.md\\n- .opencode/agent/forge.md\\n- .opencode/agent/muse.md\\n- .opencode/agent/patch.md\\n- .opencode/agent/pixel.md\\n- .opencode/agent/probe.md\\n- .opencode/agent/scribbler.md\\n- .opencode/agent/ship.md\\n- AGENTS.md\\n\\nCommit message (use exactly):\\nSimplify","notes":"PR merged: #132 — agent docs committed and AGENTS.md updated","status":"closed","priority":1,"issue_type":"task","assignee":"Ship","created_at":"2026-01-14T00:24:11.880651201-08:00","created_by":"rgardler","updated_at":"2026-01-14T00:39:12.727251108-08:00","closed_at":"2026-01-14T00:39:12.727256708-08:00","comments":[{"id":86,"issue_id":"ge-rw4","author":"rgardler","text":"git status --porcelain=1 --untracked-files=all\n\nbranch: ge-rw4/commit-agent-docs\n\nlast commit: 2d3cad9 Simplify agent definitions by moving common items to AGENTS.md. Better default permissions for build.md. Clearer delegation path.\n\nhead: 2d3cad98457e8f9b92b2056080e56c6a359fe6e0\n","created_at":"2026-01-14T08:24:43Z"},{"id":89,"issue_id":"ge-rw4","author":"rgardler","text":"Failure while creating PR or pushing branch. Last command: git push -u origin ge-rw4/commit-agent-docs\nExit code: 1\n","created_at":"2026-01-14T08:33:28Z"},{"id":90,"issue_id":"ge-rw4","author":"rgardler","text":"PR URL: https://github.com/TheWizardsCode/GEngine/pull/132\ngit rev-parse --abbrev-ref HEAD: ge-rw4/commit-agent-docs\ngit log -1 --oneline: e52b7b5 chore: bd sync - persist issue state (ge-rw4 PR)\ngit rev-parse HEAD: e52b7b58a4abb66b634cc41b2e8cd7f12013e10a\ngit status --porcelain=1 --untracked-files=all:\n\n","created_at":"2026-01-14T08:35:14Z"},{"id":93,"issue_id":"ge-rw4","author":"rgardler","text":"PR merged: https://github.com/TheWizardsCode/GEngine/pull/132\n\nGit outputs (after syncing and switching to main):\nBranch: main\nLast commit: 480e10e Simplify agent definitions by moving common items to AGENTS.md. Better default permissions for build.md. Clearer delegation path. (#132)\nStatus:\n\nbd sync output:\n✓ Sync complete\n\nNotes:\n- Agent docs PR (#132) merged; AGENTS.md updated and agent doc files consolidated.\n- Local branch ge-rw4/commit-agent-docs exists and was pushed; you may delete it remotely if desired (no destructive actions performed here).","created_at":"2026-01-14T08:39:12Z"},{"id":95,"issue_id":"ge-rw4","author":"rgardler","text":" delegate-123/add-delegate-convention\n delegate-command/update-build-md\n feature/ge-urs-ignore-artifacts\n ge-2b0/playwright-prs-only\n ge-hch-ge-hch.4/request-patch\n ge-hch.3.2/stable-story\n ge-rw4/commit-agent-docs\n* main\n","created_at":"2026-01-14T08:39:26Z"},{"id":97,"issue_id":"ge-rw4","author":"rgardler","text":"Local branch cleanup performed by Ship.\n\nDeleted branches and notes (or skips):\n\n$(cat \"$DELETED_LIST_FILE\")\n\nBranches present after cleanup:\n\n$(cat /tmp/branches_after.txt)\n\nWorking tree status (porcelain):\n\n$(cat /tmp/status_after.txt)\n","created_at":"2026-01-14T08:40:42Z"},{"id":98,"issue_id":"ge-rw4","author":"rgardler","text":"Local branch cleanup performed by Ship.\n\nDeleted branches and notes:\n$(cat /tmp/tmp.J7eIyLYU6G)\n\nBranches present after cleanup:\n$(cat /tmp/branches_after.txt)\n\nWorking tree status (porcelain):\n$(cat /tmp/status_after.txt)\n","created_at":"2026-01-14T08:40:55Z"},{"id":100,"issue_id":"ge-rw4","author":"rgardler","text":"PR: https://github.com/TheWizardsCode/GEngine/pull/133\nBranch: ge-2hh/commit-uncommitted\nCommit: 7dcbf7e chore: persist AGENTS.md and bd state (include merged PRs #131 #132)\nSHA: 7dcbf7e5a9936da6cea43c667a5b7d4dc5da4ec8\nStatus:","created_at":"2026-01-14T08:47:00Z"}]} {"id":"ge-s2q","title":"Implement: web/demo skeleton (InkJS integration)","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-05T23:10:10.569697121-08:00","created_by":"rgardler","updated_at":"2026-01-06T02:46:13.725365368-08:00","closed_at":"2026-01-06T02:46:13.725374498-08:00","dependencies":[{"issue_id":"ge-s2q","depends_on_id":"ge-hch.1.2.2","type":"discovered-from","created_at":"2026-01-05T23:10:10.574207891-08:00","created_by":"rgardler"}]} {"id":"ge-sty","title":"Remove legacy '/implement' references — make implement-skill standalone","description":"Update repository to remove legacy '/implement' slash-command references and make the implement-skill a standalone 'implement' skill.\\n\\nBackground:\\n- .opencode/skill/implement-skill/SKILL.md was updated to remove slash-command aliases and describe invocation as (SKILL.md already updated). Remaining repo references to the legacy '/implement' command must be removed or rewritten to reference the skill or plain .\\n\\nAcceptance criteria (definition of done):\\n1. All references to the legacy '/implement' command in repository docs and command files are removed or rewritten to reference the implement skill as (no leading slash).\\n2. .opencode/skill/implement-skill/SKILL.md remains present and correct.\\n3. Update any workflow docs to use (or for CLI) and remove guidance that mentions slash-prefixed input as required.\\n4. Create a short PR on branch implement-skill/remove-slash-alias (don't merge) with the edits.\\n5. Add a bd comment summarizing files changed and any follow-up beads created.\\n\\nFiles to update (non-exhaustive — discover additional occurrences as you search):\\n- .opencode/command/implement.md\\n- docs/dev/Workflow.md\\n- .opencode/command/wf-help.md\\n- docs/dev/README or other docs referencing '/implement' if found\\n\\nNotes/constraints:\\n- Do NOT edit .beads/issues.jsonl directly; use bd for any beads updates.\\n- Preserve existing semantics: the skill must update existing beads by id (do not change semantics of bd update behavior).\\n\\nAssignee: Patch\\n,--json:true}","status":"closed","priority":1,"issue_type":"chore","assignee":"Patch","created_at":"2026-01-14T22:49:51.26445498-08:00","created_by":"rgardler","updated_at":"2026-01-14T23:25:49.178311257-08:00","closed_at":"2026-01-14T23:25:49.178311257-08:00","close_reason":"Merged PR and updated main (implement skill replaces legacy command)","comments":[{"id":143,"issue_id":"ge-sty","author":"rgardler","text":"Handoff to Patch (Implementation AI):\n\nSummary:\n- Purpose: Remove legacy '/implement' slash-command references and make the implement-skill standalone (invoked as `implement `).\n- I updated the skill SKILL.md to remove slash-command aliasing: .opencode/skill/implement-skill/SKILL.md (edited).\n\nWork to do (acceptance criteria):\n1) Replace or remove all occurrences of the legacy '/implement' token in repository docs and command guidance so they reference the implement skill as `implement` (no leading slash) or indicate the CLI form `waif implement \" to update docs consistently.\n3) Edit the files listed above, run tests/linters, and open PR.\n4) If changes affect runtime code (parsers, CLI helpers, bot handlers), add short notes in the PR and create follow-up beads if the change expands scope.\n\nDelegate:\n- delegate(to: Patch)\n\nActor: @Build\n","created_at":"2026-01-15T06:50:19Z"},{"id":144,"issue_id":"ge-sty","author":"rgardler","text":"PR merged and changes included in main. Closing this chore. If you need follow-ups (eg update beads that mention '/implement'), create a new chore or reopen.\n\nFiles changed: deleted .opencode/command/implement.md; updated docs/dev/Workflow.md and .opencode/command/wf-help.md to reference the implement skill; added .opencode/skill/implement-skill/SKILL.md.\n\nAction: closing ge-sty as completed.","created_at":"2026-01-15T07:25:46Z"}]} {"id":"ge-sxl","title":"Ongoing Maintence (Chores)","description":"This is a top level epic that is used as an ongoing epic to act as a parent to chores that are identified during development work.","status":"tombstone","priority":2,"issue_type":"epic","owner":"ross@gardler.org","created_at":"2026-01-19T02:48:06.559468168-08:00","created_by":"Ross Gardler","updated_at":"2026-01-19T02:50:50.668335399-08:00","deleted_at":"2026-01-19T02:50:50.668335399-08:00","deleted_by":"daemon","delete_reason":"delete","original_type":"epic"} {"id":"ge-u9k","title":"Retire CONTEXT_PACK doc","description":"## Goal\nRemove docs/dev/CONTEXT_PACK.md and scrub any references so docs stay current.\n\n## Acceptance Criteria\n- [ ] docs/dev/CONTEXT_PACK.md deleted from repo\n- [ ] Search repo to ensure no remaining references to CONTEXT_PACK\n- [ ] Document history noted in bd comments\n\n## Files Likely Touched\n- docs/dev/CONTEXT_PACK.md\n- docs/* referencing the file\n","status":"closed","priority":2,"issue_type":"task","assignee":"@OpenCode","created_at":"2026-01-16T19:44:32.44048446-08:00","created_by":"rgardler","updated_at":"2026-01-16T19:51:42.314085468-08:00","closed_at":"2026-01-16T19:51:42.314085468-08:00","close_reason":"Completed","comments":[{"id":191,"issue_id":"ge-u9k","author":"rgardler","text":"Removed legacy docs/dev/CONTEXT_PACK.md per request. Repo search shows no remaining file references outside historical bead metadata.","created_at":"2026-01-17T03:51:25Z"}]} +{"id":"ge-un2","title":"Parent: Test parent/child relationship","description":"escription","status":"tombstone","priority":2,"issue_type":"epic","owner":"ross@gardler.org","created_at":"2026-01-19T18:37:53.294711183-08:00","created_by":"Ross Gardler","updated_at":"2026-01-19T18:38:32.541366295-08:00","deleted_at":"2026-01-19T18:38:32.541366295-08:00","deleted_by":"daemon","delete_reason":"delete","original_type":"epic"} {"id":"ge-urs","title":"Make all agents have wider default permissions, deny rather than allow","description":"Aborting the work to update agent delegation guidance; closing ge-urs per Producer request.\n\nActions taken:\n- Closed PR #130 and deleted branch ge-urs/complete-agent-perms.\n- Reverted local changes and ensured branch removed.\n\nIf you want to retry a narrower change in the future, create a new bead with explicit scope.\n","status":"closed","priority":0,"issue_type":"task","assignee":"forge","created_at":"2026-01-13T20:20:28.139994108-08:00","created_by":"rgardler","updated_at":"2026-01-13T22:48:07.307196907-08:00","closed_at":"2026-01-13T22:48:07.307204824-08:00","comments":[{"id":83,"issue_id":"ge-urs","author":"rgardler","text":"Rationale:\n- ge-urs was merged but some agent files (e.g., .opencode/agent/patch.md) still have permissive or missing deny-by-default entries. We need a consistent, conservative permission set across all .opencode/agent/*.md files.\n\nScope:\n- Inspect all files under .opencode/agent/*.md and ensure each has a permission block that follows the deny-by-default template (no blanket \"*\": allow for bash). Update patch.md and any other agents missing the template.\n\nAcceptance criteria (Definition of Done):\n1. All files under .opencode/agent/*.md include a permissive/deny-by-default permission section matching the standard template found in .opencode/agent/forge.md.\n2. No file contains a wildcard \"*\": allow for bash or equivalent permissive entries.\n3. Add or update .opencode/agent/PERMISSIONS.md describing the template and a short rationale.\n4. Create scripts/check-agent-permissions.sh that exits non-zero if any .opencode/agent/*.md contains a wildcard allow entry.\n5. Open a PR from branch feature/ge-urs-complete-agent-perms with changes, include bd comment linking the PR, and request review from @forge and @rgardler.\n\nConstraints & timebox:\n- Timebox: 48 hours. Priority: high.\n- Only edit .opencode/agent/*.md, .opencode/agent/PERMISSIONS.md, and scripts/check-agent-permissions.sh. Do not modify CI workflows or other code without Producer approval.\n\nDeliverables:\n- PR URL (in bd comment) with changes.\n- bd comment on ge-urs noting files changed, commands run, and verification steps.\n\nRelated issues:\n- ge-urs (this issue)\n\nActor: Build\n","created_at":"2026-01-14T06:16:19Z"},{"id":84,"issue_id":"ge-urs","author":"rgardler","text":"Rationale:\n- ge-urs was merged but some agent files (e.g., .opencode/agent/patch.md) still have permissive or missing deny-by-default entries. We need a consistent, conservative permission set across all .opencode/agent/*.md files.\n\nScope:\n- Inspect all files under .opencode/agent/*.md and ensure each has a permission block that follows the deny-by-default template (no blanket \"*\": allow for bash). Update patch.md and any other agents missing the template.\n\nAcceptance criteria (Definition of Done):\n1. All files under .opencode/agent/*.md include a permissive/deny-by-default permission section matching the standard template found in .opencode/agent/forge.md.\n2. No file contains a wildcard \"*\": allow for bash or equivalent permissive entries.\n3. Add or update .opencode/agent/PERMISSIONS.md describing the template and a short rationale.\n4. Create scripts/check-agent-permissions.sh that exits non-zero if any .opencode/agent/*.md contains a wildcard allow entry.\n5. Open a PR from branch feature/ge-urs-complete-agent-perms with changes, include bd comment linking the PR, and request review from @forge and @rgardler.\n\nConstraints & timebox:\n- Timebox: 48 hours. Priority: high.\n- Only edit .opencode/agent/*.md, .opencode/agent/PERMISSIONS.md, and scripts/check-agent-permissions.sh. Do not modify CI workflows or other code without Producer approval.\n\nDeliverables:\n- PR URL (in bd comment) with changes.\n- bd comment on ge-urs noting files changed, commands run, and verification steps.\n\nRelated issues:\n- ge-urs (this issue)\n\nActor: Build\n","created_at":"2026-01-14T06:16:22Z"},{"id":85,"issue_id":"ge-urs","author":"rgardler","text":"@patch — Please take ownership of completing ge-urs for the agent permission updates.\n\nScope (please implement):\n- Update .opencode/agent/patch.md so its permission block follows the deny-by-default template (see .opencode/agent/forge.md for canonical example).\n- If you find other agents missing the deny-by-default entry, you may update only .opencode/agent/patch.md OR notify Build in this thread if you prefer to update multiple agent files (we can reassign or coordinate).\n\nAcceptance criteria (Definition of Done):\n1. .opencode/agent/patch.md contains a permission block without a wildcard \"*\": allow and follows the template used in forge.md (dangerous commands set to ask, general actions denied unless explicit).\n2. Create or update .opencode/agent/PERMISSIONS.md with a one-paragraph rationale and the template (if it does not already exist).\n3. If you change any files, open a PR from a feature branch (e.g., feature/ge-urs-complete-patch) with the changes and add a bd comment linking the PR. Include files changed in the bd comment.\n4. Reply here with \"Accepted\" and an ETA, or state blockers if you cannot accept.\n\nConstraints & timebox:\n- Do not edit CI workflows or other unrelated files without Producer approval.\n- Timebox: 48 hours.\n\nActor: Build (requesting)\n","created_at":"2026-01-14T06:19:34Z"}]} {"id":"ge-wdm","title":"refactor(validate-demo): investigate skipped Playwright demo test","status":"closed","priority":2,"issue_type":"task","assignee":"probe","created_at":"2026-01-12T00:34:02.866687423-08:00","created_by":"rgardler","updated_at":"2026-01-16T02:09:45.976155116-08:00","closed_at":"2026-01-16T02:09:45.976155116-08:00","close_reason":"Auto-close: cleanup per status-skill","labels":["refactor"],"comments":[{"id":66,"issue_id":"ge-wdm","author":"rgardler","text":"Diagnostics (Probe): Playwright demo smoke suite currently fails locally because server is not started; page.goto http://127.0.0.1:4173/demo/ => ERR_CONNECTION_REFUSED for all tests. Command: npx playwright test tests/demo.smoke.spec.ts --reporter=list. Skip behavior: test 'choice can be selected via tap (touch)' includes test.skip when context lacks hasTouch; in this run hasTouch=true for chromium-touch project so it attempted and failed for same server reason, not skipped. Need to start dev server (e.g., npm run dev or npm run preview) with baseURL 4173 or use webServer in Playwright config. To repro skip, run chromium-desktop only or context with hasTouch=false; otherwise it runs. Next steps: add webServer to config or document pre-req; re-run with server active.","created_at":"2026-01-12T09:46:35Z"},{"id":160,"issue_id":"ge-wdm","author":"rgardler","text":"Auto-closing per status-skill recommendation: no linked branches/PRs and not an epic. If this is incorrect, please reopen or add a comment.","created_at":"2026-01-16T10:09:45Z"}]} {"id":"ge-ykj","title":"Character Voice Scorer","description":"Match dialogue to character voice profiles.\n\n## Context\nDeferred from ge-hch.5.15 (AI Director Implementation). Currently a placeholder returning 0.3.\n\n## Player Experience Change\nCharacters in AI branches will speak consistently with their established voice. Players won't notice jarring out-of-character dialogue.\n\n## Acceptance Criteria\n- [ ] Extract character dialogue from branch content\n- [ ] Compare against character voice profiles\n- [ ] Compute voice consistency via embedding distance\n- [ ] Return risk score for out-of-character dialogue\n\n## Dependencies\n- ge-hch.5.15.4 (Embedding Service)\n- ge-hch.5.15 completion","status":"open","priority":3,"issue_type":"feature","created_at":"2026-01-16T15:04:58.213323804-08:00","created_by":"rgardler","updated_at":"2026-01-16T15:04:58.213323804-08:00","labels":["stage:idea"],"dependencies":[{"issue_id":"ge-ykj","depends_on_id":"ge-hch.5.15","type":"discovered-from","created_at":"2026-01-16T15:04:58.214452018-08:00","created_by":"rgardler"}]} diff --git a/jest.config.js b/jest.config.js index 1505418..52f2349 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,6 +1,6 @@ /** @type {import('jest').Config} */ module.exports = { testEnvironment: 'jsdom', - testMatch: ['**/tests/unit/**/*.test.[jt]s', '**/tests/validate-story/**/*.test.[jt]s', '**/tests/replay/**/*.spec.[jt]s'], + testMatch: ['**/tests/unit/**/*.test.[jt]s', '**/tests/validate-story/**/*.test.[jt]s', '**/tests/replay/**/*.spec.[jt]s', '**/tests/integration/**/*.test.[jt]s'], setupFilesAfterEnv: ['/jest.setup.js'], }; diff --git a/server/telemetry/README.md b/server/telemetry/README.md index 8ddaec6..0a9d042 100644 --- a/server/telemetry/README.md +++ b/server/telemetry/README.md @@ -1,52 +1,66 @@ -Telemetry Receiver Prototype - -Purpose: - -This receiver is a development prototype for collecting telemetry events emitted by the Director and related runtime components. It is intended for local testing and experimentation only — not for production use. Use it to: - -- Capture and inspect `director_decision` events emitted by the Director during playtests. -- Exercise telemetry payload shapes and validate downstream processing or analysis scripts. -- Provide a simple, disposable storage backend (newline-delimited JSON) for quick local debugging. - -Do not rely on this receiver for production telemetry: it has no authentication, no retention/rotation, and minimal error handling. - -Run locally: - -- Node (>= 14) is required -- Start the receiver: - - PORT=4005 node server/telemetry/receiver.js - -It listens on `/` for HTTP POST JSON payloads. - -Accepted events: - -Only events with `type: "director_decision"` (or `event_type` or nested `event.type`) are accepted and persisted to `server/telemetry/events.ndjson`. - -Expected payload shape (example): - - { - "type": "director_decision", - "decision": "accept", - "reason": "low_risk", - "meta": { "user": "test" } - } - -Example curl test: - - curl -v -X POST \ - -H "Content-Type: application/json" \ - -d '{"type":"director_decision","decision":"accept","meta":{"user":"test"}}' \ - http://localhost:4005/ - -Expected responses: -- 200 {"ok":true} for valid director_decision events -- 400 {"error":"Invalid or unsupported event type"} for invalid event types -- 400 {"error":"Invalid JSON"} for malformed JSON -- 404 for non-POST or other paths - -Storage: -- Events are appended to `server/telemetry/events.ndjson` as newline-delimited JSON lines with a `received_at` timestamp. - -Notes / next steps: -- This is intentionally minimal. For follow-up work consider adding SQLite persistence, simple schema validation, or basic authentication before using in shared environments. +Telemetry receiver (dev prototype) + +Purpose +------- +Lightweight development receiver that accepts POSTed JSON events and persists director decision telemetry for local analysis. + +What it does +------------ +- Accepts POST requests to `/` with a JSON body. +- Validates that the event represents a `director_decision` (accepts payloads with `type: "director_decision"` or same under `event_type` or `event.type`). +- Appends accepted events as NDJSON lines to `server/telemetry/events.ndjson` (dev ingestion store). + +Run locally +----------- +```bash +# starts the receiver on port 4005 by default +node server/telemetry/receiver.js + +# to choose a different port (useful in tests): +PORT=0 node server/telemetry/receiver.js +``` + +The process prints the listening URL to stdout when ready, e.g. `Telemetry receiver listening on http://localhost:4005/`. + +API (single endpoint) +--------------------- +- POST / + - Content-Type: application/json + - Body: arbitrary JSON representing an event + - Success (200): when the payload identifies as a `director_decision` and was persisted + - Client error (400): when payload is invalid JSON or not a supported event type + - Server error (500): when writing to storage failed + +Example payload (director_decision) +---------------------------------- +```json +{ + "type": "director_decision", + "proposal_id": "p1", + "decision": "approve", + "riskScore": 0.12, + "reason": "low_risk", + "metrics": { "latencyMs": 120 } +} +``` + +Curl example +------------ +```bash +curl -X POST http://localhost:4005/ \ + -H 'Content-Type: application/json' \ + -d '{"type":"director_decision","proposal_id":"p1","decision":"approve","riskScore":0.12}' +``` + +Inspecting persisted events +--------------------------- +Events are appended to `server/telemetry/events.ndjson` as one JSON object per line. To inspect recent events: + +```bash +tail -n 50 server/telemetry/events.ndjson | jq . +``` + +Development notes +----------------- +- This receiver is intentionally small and intended for dev/testing only. Production work (SQLite storage, schema validation, auth/token protection, log rotation) is tracked in `ge-apq.1` and should be implemented before using this in production. +- The receiver uses `server/telemetry/backend-ndjson.js` as the storage backend; swap or extend backends as needed. diff --git a/server/telemetry/backend-ndjson.js b/server/telemetry/backend-ndjson.js new file mode 100644 index 0000000..dd40223 --- /dev/null +++ b/server/telemetry/backend-ndjson.js @@ -0,0 +1,24 @@ +'use strict' + +const fs = require('fs') +const path = require('path') + +const LOG_DIR = path.join(__dirname) +const LOG_FILE = path.join(LOG_DIR, 'events.ndjson') + +function ensureDir() { + if (!fs.existsSync(LOG_DIR)) fs.mkdirSync(LOG_DIR, { recursive: true }) +} + +function emit(event) { + try { + ensureDir() + // If event looks like a wrapped { received_at, payload } keep that shape + if (event && event.received_at && event.payload) fs.appendFileSync(LOG_FILE, JSON.stringify(event) + '\n', 'utf8') + else fs.appendFileSync(LOG_FILE, JSON.stringify({ received_at: new Date().toISOString(), payload: event }) + '\n', 'utf8') + } catch (e) { + console.error('ndjson backend write failed', e) + } +} + +module.exports = { emit } diff --git a/server/telemetry/receiver.js b/server/telemetry/receiver.js index 4922e3a..9566e87 100644 --- a/server/telemetry/receiver.js +++ b/server/telemetry/receiver.js @@ -5,6 +5,7 @@ const http = require('http'); const fs = require('fs'); const path = require('path'); +const ndjsonBackend = require('../telemetry/backend-ndjson') const PORT = process.env.PORT ? Number(process.env.PORT) : 4005; const DATA_DIR = path.resolve(__dirname); @@ -45,21 +46,19 @@ const server = http.createServer((req, res) => { return; } - const line = JSON.stringify({ received_at: new Date().toISOString(), payload }); - - fs.appendFile(OUTFILE, line + '\n', (err) => { - if (err) { - console.error('Failed to persist event', err); - res.statusCode = 500; - res.setHeader('Content-Type', 'application/json'); - res.end(JSON.stringify({ error: 'Failed to persist event' })); - return; - } - + const event = { received_at: new Date().toISOString(), payload }; + // write via simple ndjson backend (appends to events.ndjson) + try { + ndjsonBackend.emit(event); res.statusCode = 200; res.setHeader('Content-Type', 'application/json'); res.end(JSON.stringify({ ok: true })); - }); + } catch (err) { + console.error('Failed to persist event', err); + res.statusCode = 500; + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify({ error: 'Failed to persist event' })); + } }); req.on('error', (err) => { diff --git a/src/runtime/subscribers/telemetry.js b/src/runtime/subscribers/telemetry.js index 70bd2f0..09d9a38 100644 --- a/src/runtime/subscribers/telemetry.js +++ b/src/runtime/subscribers/telemetry.js @@ -1,30 +1,31 @@ // Telemetry subscriber for runtime HookManager // Emits console-based telemetry events; in prod this should hook into telemetry module -module.exports = function createTelemetrySubscriber(telemetry = console) { +const { defaultTelemetry } = require('../../telemetry/emitter'); + +// Map runtime hook names to telemetry event types +const HOOK_EVENT_MAP = { + pre_inject: 'generation', + post_inject: 'presentation', + pre_checkpoint: 'validation', + post_checkpoint: 'outcome' +}; + +module.exports = function createTelemetrySubscriber(telemetryBackend) { + const telemetry = telemetryBackend || defaultTelemetry; return { name: 'runtime-telemetry-subscriber', async pre_inject(payload) { - try { - telemetry.log('telemetry.event', { event: 'pre_inject', payload }); - } catch (err) { - // swallow - } + try { telemetry.emit(HOOK_EVENT_MAP.pre_inject, payload); } catch (err) { } }, async post_inject(payload) { - try { - telemetry.log('telemetry.event', { event: 'post_inject', payload }); - } catch (err) {} + try { telemetry.emit(HOOK_EVENT_MAP.post_inject, payload); } catch (err) { } }, async pre_checkpoint(payload) { - try { - telemetry.log('telemetry.event', { event: 'pre_checkpoint', payload }); - } catch (err) {} + try { telemetry.emit(HOOK_EVENT_MAP.pre_checkpoint, payload); } catch (err) { } }, async post_checkpoint(payload) { - try { - telemetry.log('telemetry.event', { event: 'post_checkpoint', payload }); - } catch (err) {} + try { telemetry.emit(HOOK_EVENT_MAP.post_checkpoint, payload); } catch (err) { } } }; }; diff --git a/src/telemetry/README.md b/src/telemetry/README.md new file mode 100644 index 0000000..e655acb --- /dev/null +++ b/src/telemetry/README.md @@ -0,0 +1,20 @@ +Telemetry module + +This lightweight telemetry module provides: + +- `src/telemetry/emitter.js` — in-memory telemetry emitter with redact-on-ingest and a simple query API for tests and local analysis. +- `src/telemetry/redact.js` — minimal PII redaction helpers. +- `src/telemetry/backends/console.js` — default backend writing concise logs to console. + +Usage (node): + +```js +const { defaultTelemetry } = require('./src/telemetry/emitter') +const consoleBackend = require('./src/telemetry/backends/console') +defaultTelemetry.addBackend(consoleBackend) +defaultTelemetry.emit('story_start', { sessionId: 's1', userEmail: 'bob@example.com' }) +``` + +Notes +- Redaction is intentionally conservative; extend `redact.js` for stricter rules. +- Buffer size defaults to 1000 events; override via `new Telemetry({bufferSize})` if needed. diff --git a/src/telemetry/backends/console.js b/src/telemetry/backends/console.js new file mode 100644 index 0000000..5bbf28c --- /dev/null +++ b/src/telemetry/backends/console.js @@ -0,0 +1,12 @@ +'use strict' + +function emit(event) { + // keep a concise log format + try { + console.log('[TELEMETRY]', event.type, event.timestamp, JSON.stringify(event.payload)) + } catch (e) { + console.log('[TELEMETRY]', event.type, event.timestamp) + } +} + +module.exports = { emit } diff --git a/src/telemetry/emitter.js b/src/telemetry/emitter.js new file mode 100644 index 0000000..d53027a --- /dev/null +++ b/src/telemetry/emitter.js @@ -0,0 +1,60 @@ +// Telemetry emitter: emits events to available backends and provides an in-memory/queryable store for tests. +'use strict' + +const { redact } = require('./redact') + +const DEFAULT_BUFFER_SIZE = 1000 + +class Telemetry { + constructor(opts = {}) { + this.bufferSize = opts.bufferSize || DEFAULT_BUFFER_SIZE + this.events = [] // circular buffer + this.backends = [] + } + + addBackend(backend) { + if (backend && typeof backend.emit === 'function') this.backends.push(backend) + } + + emit(type, payload = {}) { + const ts = new Date().toISOString() + const redacted = redact(payload) + const event = { type, timestamp: ts, payload: redacted } + // validate against schema if available + try { + const { validate } = require('./schema') + const res = validate(type, redacted) + if (!res.valid) { + // emit a validation event instead of storing the invalid payload + const v = { type: 'validation', timestamp: ts, payload: { valid: false, errors: res.errors, originalType: type } } + this._push(v) + for (const b of this.backends) { try { b.emit(v) } catch (e) {} } + return + } + } catch (e) { + // ignore schema failures + } + + this._push(event) + for (const b of this.backends) { + try { b.emit(event) } catch (e) { console.error('telemetry backend emit failed', e) } + } + } + + _push(event) { + this.events.push(event) + if (this.events.length > this.bufferSize) this.events.shift() + } + + query(filterFn) { + if (!filterFn) return this.events.slice() + return this.events.filter(filterFn) + } + + clear() { this.events = [] } +} + +// Singleton for browser/demo usage +const defaultTelemetry = new Telemetry() + +module.exports = { Telemetry, defaultTelemetry } diff --git a/src/telemetry/redact.js b/src/telemetry/redact.js new file mode 100644 index 0000000..bac58bf --- /dev/null +++ b/src/telemetry/redact.js @@ -0,0 +1,37 @@ +// Minimal PII redaction utilities used by the telemetry emitter. +'use strict' + +const PII_KEY_RE = /(email|name|ssn|phone|address|credit|card|cc|token)/i +const EMAIL_RE = /[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/i + +function isPlainObject(v) { + return v && typeof v === 'object' && !Array.isArray(v) +} + +function redactValue(v) { + if (typeof v !== 'string') return v + if (EMAIL_RE.test(v)) return '[REDACTED_EMAIL]' + // crude phone/credit detection + if (/\b\d{3}[- ]?\d{2,4}[- ]?\d{2,4}\b/.test(v)) return '[REDACTED]' + return v +} + +function redact(obj) { + if (Array.isArray(obj)) return obj.map(redact) + if (!isPlainObject(obj)) return redactValue(obj) + + const out = {} + for (const k of Object.keys(obj)) { + const v = obj[k] + if (PII_KEY_RE.test(k)) { + out[k] = typeof v === 'string' ? redactValue(v) : '[REDACTED]' + continue + } + if (Array.isArray(v)) out[k] = v.map(item => (isPlainObject(item) ? redact(item) : redactValue(item))) + else if (isPlainObject(v)) out[k] = redact(v) + else out[k] = redactValue(v) + } + return out +} + +module.exports = { redact } diff --git a/src/telemetry/schema.js b/src/telemetry/schema.js new file mode 100644 index 0000000..26e8258 --- /dev/null +++ b/src/telemetry/schema.js @@ -0,0 +1,37 @@ +// Minimal telemetry schema validator. Keeps rules simple to avoid runtime deps. +'use strict' + +function missing(field) { return `missing required field: ${field}` } + +const SCHEMAS = { + generation: { + required: ['sessionId'], + }, + validation: { + required: ['valid'], + }, + director_decision: { + required: ['proposal_id', 'decision'], + }, + presentation: { + required: ['content'], + }, + choice: { + required: ['choice_id', 'text'], + }, + outcome: { + required: ['outcome_type'], + } +} + +function validate(type, payload) { + const schema = SCHEMAS[type] + if (!schema) return { valid: false, errors: [`unknown event type: ${type}`] } + const errors = [] + for (const f of (schema.required || [])) { + if (payload == null || (typeof payload === 'object' && !(f in payload))) errors.push(missing(f)) + } + return { valid: errors.length === 0, errors } +} + +module.exports = { validate } diff --git a/tests/integration/telemetry.receiver.integration.test.js b/tests/integration/telemetry.receiver.integration.test.js new file mode 100644 index 0000000..2a6ca15 --- /dev/null +++ b/tests/integration/telemetry.receiver.integration.test.js @@ -0,0 +1,53 @@ +const path = require('path') +const fs = require('fs') +const { spawn } = require('child_process') +const http = require('http') + +const RECEIVER = path.join(__dirname, '../../server/telemetry/receiver.js') +const OUTFILE = path.join(__dirname, '../../server/telemetry/events.ndjson') + +function waitForFile(file, timeout = 3000) { + const start = Date.now() + return new Promise((resolve, reject) => { + ;(function poll() { + if (fs.existsSync(file) && fs.statSync(file).size > 0) return resolve(true) + if (Date.now() - start > timeout) return reject(new Error('timeout')) + setTimeout(poll, 100) + })() + }) +} + +describe('telemetry receiver', () => { + let child + beforeAll((done) => { + // remove outfile if exists + try { fs.unlinkSync(OUTFILE) } catch (e) {} + child = spawn(process.execPath, [RECEIVER], { stdio: ['ignore', 'pipe', 'pipe'], env: process.env }) + child.stdout.on('data', (d) => { + const s = d.toString() + if (/listening/.test(s)) done() + }) + child.stderr.on('data', (d) => {}) + }) + + afterAll(() => { if (child) child.kill() }) + + test('POST director_decision is persisted to ndjson', async () => { + const payload = JSON.stringify({ type: 'director_decision', proposal_id: 'p-test', decision: 'approve' }) + await new Promise((res, rej) => { + const req = http.request({ method: 'POST', port: 4005, path: '/', headers: { 'Content-Type': 'application/json' } }, (r) => { + expect(r.statusCode).toBe(200) + res() + }) + req.on('error', rej) + req.write(payload) + req.end() + }) + + await waitForFile(OUTFILE) + const lines = fs.readFileSync(OUTFILE, 'utf8').trim().split('\n') + const last = JSON.parse(lines[lines.length - 1]) + expect(last.payload.type).toBe('director_decision') + expect(last.payload.proposal_id).toBe('p-test') + }) +}) diff --git a/tests/unit/telemetry.emitter.integration.test.js b/tests/unit/telemetry.emitter.integration.test.js new file mode 100644 index 0000000..88987b2 --- /dev/null +++ b/tests/unit/telemetry.emitter.integration.test.js @@ -0,0 +1,20 @@ +const { defaultTelemetry } = require('../../src/telemetry/emitter') + +describe('telemetry emitter buffer', () => { + beforeEach(() => { defaultTelemetry.clear() }) + + test('emit stores redacted events in buffer and backends are called', () => { + const calls = [] + const fakeBackend = { emit: (ev) => calls.push(ev) } + defaultTelemetry.addBackend(fakeBackend) + + defaultTelemetry.emit('generation', { sessionId: 's-1', userEmail: 'alice@example.com', choice: 'X' }) + + const events = defaultTelemetry.query() + expect(events.length).toBe(1) + expect(events[0].type).toBe('generation') + // redaction should replace email + expect(JSON.stringify(events[0].payload)).toMatch('REDACTED') + expect(calls.length).toBe(1) + }) +})