bd sync: 2025-12-30 22:21:43

This commit is contained in:
Steve Yegge
2025-12-30 22:21:43 -08:00
parent b992a428dc
commit 39ab273773

View File

@@ -198,7 +198,7 @@
{"id":"bd-89f89fc0","title":"Remove unreachable RPC methods","description":"Several RPC server and client methods are unreachable and should be removed:\n\nServer methods (internal/rpc/server.go):\n- `Server.GetLastImportTime` (line 2116)\n- `Server.SetLastImportTime` (line 2123)\n- `Server.findJSONLPath` (line 2255)\n\nClient methods (internal/rpc/client.go):\n- `Client.Import` (line 311) - RPC import not used (daemon uses autoimport)\n\nEvidence:\n```bash\ngo run golang.org/x/tools/cmd/deadcode@latest -test ./...\n```\n\nImpact: Removes ~80 LOC of unused RPC code","status":"tombstone","priority":2,"issue_type":"task","created_at":"2025-10-28T16:20:02.432202-07:00","updated_at":"2025-12-25T01:21:01.952723-08:00","deleted_at":"2025-12-25T01:21:01.952723-08:00","deleted_by":"batch delete","delete_reason":"batch delete","original_type":"task"}
{"id":"bd-8b0x","title":"Remove molecule.go (simple instantiation)","description":"molecule.go uses is_template field for simple single-issue cloning. This is too simple for what molecules should be - full DAG orchestration. The use case is covered by bd mol bond with a single-issue molecule. Delete molecule.go and its commands.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-20T23:52:15.041776-08:00","updated_at":"2025-12-21T00:04:32.335849-08:00","closed_at":"2025-12-21T00:04:32.335849-08:00","dependencies":[{"issue_id":"bd-8b0x","depends_on_id":"bd-ffjt","type":"blocks","created_at":"2025-12-20T23:52:25.807967-08:00","created_by":"daemon"}]}
{"id":"bd-8ca7","title":"Merge: bd-au0.6","description":"branch: polecat/furiosa\ntarget: main\nsource_issue: bd-au0.6\nrig: beads","status":"closed","priority":1,"issue_type":"merge-request","created_at":"2025-12-23T20:42:30.870178-08:00","updated_at":"2025-12-23T21:21:57.695179-08:00","closed_at":"2025-12-23T21:21:57.695179-08:00"}
{"id":"bd-8cns","title":"gt sling --create fails to create polecat before resolving pane","description":"gt sling --create tries to resolve pane BEFORE creating the polecat, causing failure.\n\nExpected: gt sling gt-xyz gastown/newcat --create should:\n1. Create polecat if not exists\n2. Start session\n3. Hook work\n4. GUPP triggers autonomous execution\n\nActual: Fails with 'getting pane for gt-gastown-newcat: exit status 1'\n\nLocation: internal/cmd/sling.go - need to reorder operations","status":"hooked","priority":2,"issue_type":"bug","assignee":"beads/polecats/flint","created_at":"2025-12-30T21:20:59.58382-08:00","created_by":"mayor","updated_at":"2025-12-30T22:13:05.670667-08:00"}
{"id":"bd-8cns","title":"gt sling --create fails to create polecat before resolving pane","description":"gt sling --create tries to resolve pane BEFORE creating the polecat, causing failure.\n\nExpected: gt sling gt-xyz gastown/newcat --create should:\n1. Create polecat if not exists\n2. Start session\n3. Hook work\n4. GUPP triggers autonomous execution\n\nActual: Fails with 'getting pane for gt-gastown-newcat: exit status 1'\n\nLocation: internal/cmd/sling.go - need to reorder operations","status":"closed","priority":2,"issue_type":"bug","assignee":"beads/polecats/flint","created_at":"2025-12-30T21:20:59.58382-08:00","created_by":"mayor","updated_at":"2025-12-30T22:19:27.682372-08:00","closed_at":"2025-12-30T22:19:27.682372-08:00","close_reason":"Fixed in PR #4: https://github.com/steveyegge/gastown/pull/4"}
{"id":"bd-8e0q","title":"Merge: beads-ocs","description":"branch: polecat/valkyrie\ntarget: main\nsource_issue: beads-ocs\nrig: beads","status":"closed","priority":2,"issue_type":"merge-request","created_at":"2025-12-19T23:24:45.281478-08:00","updated_at":"2025-12-20T23:17:26.995706-08:00","closed_at":"2025-12-20T23:17:26.995706-08:00"}
{"id":"bd-8fgn","title":"test hash length","status":"tombstone","priority":2,"issue_type":"task","created_at":"2025-12-16T13:49:32.113843-08:00","updated_at":"2025-12-17T16:11:17.070763-08:00","deleted_at":"2025-12-17T16:11:17.070763-08:00","deleted_by":"batch delete","delete_reason":"batch delete","original_type":"task"}
{"id":"bd-8fqd","title":"Test role bead","status":"closed","priority":2,"issue_type":"role","created_at":"2025-12-27T23:37:10.275712-08:00","created_by":"mayor","updated_at":"2025-12-27T23:37:15.585821-08:00","closed_at":"2025-12-27T23:37:15.585821-08:00"}
@@ -229,6 +229,7 @@
{"id":"bd-9qj5","title":"Merge: bd-c7y5","description":"branch: polecat/toast\ntarget: main\nsource_issue: bd-c7y5\nrig: beads","status":"closed","priority":2,"issue_type":"merge-request","created_at":"2025-12-23T20:45:02.626929-08:00","updated_at":"2025-12-23T21:21:57.699742-08:00","closed_at":"2025-12-23T21:21:57.699742-08:00"}
{"id":"bd-9szg","title":"Test prefix bd","status":"tombstone","priority":2,"issue_type":"task","created_at":"2025-12-27T14:24:41.470665-08:00","created_by":"stevey","updated_at":"2025-12-27T14:24:50.420887-08:00","deleted_at":"2025-12-27T14:24:50.420887-08:00","deleted_by":"daemon","delete_reason":"delete","original_type":"task"}
{"id":"bd-9usz","title":"Test suite hangs/never finishes","description":"Running 'go test ./... -count=1' hangs indefinitely. The full test suite never completes, making it difficult to verify changes. Need to investigate which tests are hanging and fix or add timeouts.","status":"closed","priority":2,"issue_type":"bug","created_at":"2025-12-16T21:56:27.80191-08:00","updated_at":"2025-12-23T23:48:57.837606-08:00","closed_at":"2025-12-23T23:48:57.837606-08:00"}
{"id":"bd-9yvw","title":"Merge: flint-mjtmdf12","description":"branch: polecat/flint-mjtmdf12\ntarget: main\nsource_issue: flint-mjtmdf12\nrig: beads","status":"open","priority":2,"issue_type":"merge-request","created_at":"2025-12-30T22:20:42.246333-08:00","created_by":"beads/polecats/flint","updated_at":"2025-12-30T22:20:42.246333-08:00"}
{"id":"bd-a0cp","title":"Consider using types.Status in merge package for type safety","description":"The merge package uses string for status comparison (e.g., result.Status == closed, issue.Status == StatusTombstone). The types package defines Status as a type alias with validation. While the merge package needs its own Issue struct for JSONL flexibility, it could import and use types.Status for constants to get compile-time type checking. Current code: if left == closed || right == closed. Could be: if left == string(types.StatusClosed). This is low priority since string comparison works correctly. Files: internal/merge/merge.go:44, 488, 501-521","status":"closed","priority":4,"issue_type":"task","created_at":"2025-12-05T16:37:10.690424-08:00","updated_at":"2025-12-30T18:12:30.980592-08:00","closed_at":"2025-12-30T15:54:45.570222-08:00","close_reason":"Added StatusClosed constant derived from types.StatusClosed and replaced hardcoded strings with the constant for type safety"}
{"id":"bd-a15d","title":"Add test files for internal/storage","description":"The internal/storage package has no test files at all. This package provides the storage interface abstraction.\n\nCurrent coverage: N/A (no test files)\nTarget: Add basic interface tests","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-13T20:43:11.363017-08:00","updated_at":"2025-12-23T23:56:07.002735-08:00","closed_at":"2025-12-23T23:56:07.002735-08:00"}
{"id":"bd-a1t0","title":"Merge: opal-1767138520240","description":"branch: polecat/opal-1767138520240\ntarget: main\nsource_issue: opal-1767138520240\nrig: beads","status":"closed","priority":2,"issue_type":"merge-request","created_at":"2025-12-30T15:59:09.905942-08:00","created_by":"beads/polecats/opal","updated_at":"2025-12-30T18:12:30.970486-08:00","closed_at":"2025-12-30T18:11:07.988358-08:00"}
@@ -308,6 +309,7 @@
{"id":"bd-cfxq","title":"Merge: topaz-1767106269860","description":"branch: polecat/topaz-1767106269860\ntarget: main\nsource_issue: topaz-1767106269860\nrig: beads","status":"closed","priority":2,"issue_type":"merge-request","created_at":"2025-12-30T07:18:49.114417-08:00","created_by":"beads/polecats/topaz","updated_at":"2025-12-30T18:12:30.985385-08:00","closed_at":"2025-12-30T18:11:08.052794-08:00"}
{"id":"bd-cils","title":"Work on beads-2nh: Fix gt spawn --issue to find issues in...","description":"Work on beads-2nh: Fix gt spawn --issue to find issues in rig's beads database. When done, submit MR (not PR) to integration branch for Refinery.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-19T22:55:47.573854-08:00","updated_at":"2025-12-20T00:49:51.927884-08:00","closed_at":"2025-12-19T23:28:28.605343-08:00"}
{"id":"bd-cj2e","title":"bd update --parent: allow reparenting issues","description":"**Request:** Add `--parent` flag to `bd update` command.\n\n**Use case:** When renaming/migrating an epic (e.g., gt-oki8p → gt-liftoff), need to reparent child issues to the new epic.\n\n**Current workaround:** None clean - must delete and recreate children, or manually edit JSONL.\n\n**Proposed:**\n```bash\nbd update gt-j0gx2 --parent=gt-liftoff\n```\n\n**Note:** `bd create` already has `--parent` flag, so the semantics are established.","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-12-27T21:42:44.396998-08:00","created_by":"mayor","updated_at":"2025-12-27T22:17:12.346147-08:00","closed_at":"2025-12-27T22:17:12.346147-08:00"}
{"id":"bd-cm5g","title":"Merge: basalt-mjtme50i","description":"branch: polecat/basalt-mjtme50i\ntarget: main\nsource_issue: basalt-mjtme50i\nrig: beads","status":"open","priority":2,"issue_type":"merge-request","created_at":"2025-12-30T22:20:38.32952-08:00","created_by":"beads/polecats/basalt","updated_at":"2025-12-30T22:20:38.32952-08:00"}
{"id":"bd-cnwx","title":"Refactor mol.go: split 1200+ line file into subcommands","description":"## Problem\n\ncmd/bd/mol.go has grown to 1200+ lines with all molecule subcommands in one file.\n\n## Current State\n- mol.go: 1218 lines (bond, spawn, run, distill, catalog, show, etc.)\n- Hard to navigate, review, and maintain\n\n## Proposed Structure\nSplit into separate files by subcommand:\n```\ncmd/bd/\n├── mol.go # Root command, shared helpers\n├── mol_bond.go # bd mol bond\n├── mol_spawn.go # bd mol spawn \n├── mol_run.go # bd mol run\n├── mol_distill.go # bd mol distill\n├── mol_catalog.go # bd mol catalog\n├── mol_show.go # bd mol show\n└── mol_test.go # Tests (already separate)\n```\n\n## Benefits\n- Easier code review\n- Better separation of concerns\n- Simpler navigation\n- Each subcommand self-contained","status":"closed","priority":2,"issue_type":"chore","created_at":"2025-12-21T11:30:58.832192-08:00","updated_at":"2025-12-21T11:42:49.390824-08:00","closed_at":"2025-12-21T11:42:49.390824-08:00"}
{"id":"bd-co29","title":"Merge: bd-n386","description":"branch: polecat/immortan\ntarget: main\nsource_issue: bd-n386\nrig: beads","status":"closed","priority":2,"issue_type":"merge-request","created_at":"2025-12-23T20:41:45.644113-08:00","updated_at":"2025-12-23T21:21:57.70152-08:00","closed_at":"2025-12-23T21:21:57.70152-08:00"}
{"id":"bd-crgr","title":"GH#517: Claude sets priority wrong on new install","description":"Claude uses 'medium/high/low' for priority instead of P0-P4. Update bd prime/onboard output to be clearer about priority syntax. See GitHub issue #517.","status":"tombstone","priority":2,"issue_type":"bug","created_at":"2025-12-16T01:03:34.803084-08:00","updated_at":"2025-12-17T16:11:17.070763-08:00","deleted_at":"2025-12-17T16:11:17.070763-08:00","deleted_by":"batch delete","delete_reason":"batch delete","original_type":"bug"}
@@ -503,7 +505,7 @@
{"id":"bd-ldb0","title":"Rename ephemeral → wisp throughout codebase","description":"## The Change\n\nRename 'ephemeral' to 'wisp' throughout the beads codebase.\n\n## Why\n\n**Ephemeral** is:\n- 4 syllables (too long)\n- Greek/academic (doesn't match bond/burn/squash)\n- Overused in tech (K8s, networking, storage)\n- Passive/descriptive\n\n**Wisp** is:\n- 1 syllable (matches bond/burn/squash)\n- Evocative - you can SEE a wisp\n- Steam engine metaphor - Gas Town is engines, steam wisps rise and dissipate\n- Will-o'-the-wisp - transient spirits that guide then vanish\n- Unique - nobody else uses it\n\n## The Steam Engine Metaphor\n\n```\nEngine does work → generates steam\nSteam wisps rise → execution trace\nSteam condenses → digest (distillate)\nSteam dissipates → cleaned up (burned)\n```\n\n## Full Vocabulary\n\n| Term | Meaning |\n|------|---------|\n| bond | Attach proto to work (creates wisps) |\n| wisp | Temporary execution step |\n| squash | Condense wisps into digest |\n| burn | Destroy wisps without record |\n| digest | Permanent condensed record |\n\n## Changes Required\n\n### Code\n- `Ephemeral bool` → `Wisp bool` in types/issue.go\n- `--ephemeral` flag → remove (wisp is default)\n- `--persistent` flag → keep as opt-out\n- `bd cleanup --ephemeral` → `bd cleanup --wisps`\n- Update all references in mol_*.go files\n\n### Docs\n- Update all documentation\n- Update CLAUDE.md examples\n- Update CLI help text\n\n### Database Migration\n- Add migration to rename field (or keep internal name, just change API)\n\n## Example Usage After\n\n```bash\nbd mol bond mol-polecat-work # Creates wisps (default)\nbd mol bond mol-xxx --persistent # Creates permanent issues\nbd mol squash bd-xxx # Condenses wisps → digest\nbd cleanup --wisps # Clean old wisps\nbd list --wisps # Show wisp issues\n```","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-21T14:44:41.576068-08:00","updated_at":"2025-12-22T00:32:31.153738-08:00","closed_at":"2025-12-22T00:32:31.153738-08:00"}
{"id":"bd-lfak","title":"bd preflight: PR readiness checks for contributors","description":"## Vision\n\nEncode project-specific institutional knowledge into executable checks. CONTRIBUTING.md is documentation that's read once and forgotten; `bd preflight` is documentation that runs at exactly the right moment.\n\n## Problem Statement\n\nContributors face a \"last mile\" problem - they do the work but stumble on project-specific gotchas at PR time:\n- Nix vendorHash gets stale when go.sum changes\n- Beads artifacts leak into PRs (see bd-umbf for namespace solution)\n- Version mismatches between version.go and default.nix\n- Tests/lint not run locally before pushing\n- Other project-specific checks that only surface when CI fails\n\nThese are too obscure to remember, exist in docs nobody reads end-to-end, and waste CI round-trips.\n\n## Why beads?\n\nBeads already has a foothold in the contributor workflow. It knows:\n- Git state (staged files, branch, dirty status)\n- Project structure\n- The specific issue being worked on\n- Project-specific configuration\n\n## Proposed Interface\n\n### Tier 1: Checklist Mode (v1)\n\n $ bd preflight\n PR Readiness Checklist:\n\n [ ] Tests pass: go test -short ./...\n [ ] Lint passes: golangci-lint run ./...\n [ ] No beads pollution: check .beads/issues.jsonl diff\n [ ] Nix hash current: go.sum unchanged or vendorHash updated\n [ ] Version sync: version.go matches default.nix\n\n Run 'bd preflight --check' to validate automatically.\n\n### Tier 2: Check Mode (v2)\n\n $ bd preflight --check\n ✓ Tests pass\n ✓ Lint passes\n ⚠ Beads pollution: 3 issues in diff - are these project issues or personal?\n ✗ Nix hash stale: go.sum changed, vendorHash needs update\n Fix: sha256-KRR6dXzsSw8OmEHGBEVDBOoIgfoZ2p0541T9ayjGHlI=\n ✓ Version sync\n\n 1 error, 1 warning. Run 'bd preflight --fix' to auto-fix where possible.\n\n### Tier 3: Fix Mode (v3)\n\n $ bd preflight --fix\n ✓ Updated vendorHash in default.nix\n ⚠ Cannot auto-fix beads pollution - manual review needed\n\n## Checks to Implement\n\n| Check | Description | Auto-fixable |\n|-------|-------------|--------------|\n| tests | Run go test -short ./... | No |\n| lint | Run golangci-lint | Partial (gofmt) |\n| beads-pollution | Detect personal issues in diff | No (see bd-umbf) |\n| nix-hash | Detect stale vendorHash | Yes (if nix available) |\n| version-sync | version.go matches default.nix | Yes |\n| no-debug | No TODO/FIXME/console.log | Warn only |\n| clean-stage | No unintended files staged | Warn only |\n\n## Future: Configuration\n\nMake checks configurable per-project via .beads/preflight.yaml:\n\n preflight:\n checks:\n - name: tests\n run: go test -short ./...\n required: true\n - name: no-secrets\n pattern: \"**/*.env\"\n staged: deny\n - name: custom-check\n run: ./scripts/validate.sh\n\nThis lets any project using beads define their own preflight checks.\n\n## Implementation Phases\n\n### Phase 1: Static Checklist\n- Implement bd preflight with hardcoded checklist for beads\n- No execution, just prints what to check\n- Update CONTRIBUTING.md to reference it\n\n### Phase 2: Automated Checks\n- Implement bd preflight --check\n- Run tests, lint, detect stale hashes\n- Clear pass/fail/warn output\n\n### Phase 3: Auto-fix\n- Implement bd preflight --fix\n- Fix vendorHash, version sync\n- Integrate with bd-umbf solution for pollution\n\n### Phase 4: Configuration\n- .beads/preflight.yaml support\n- Make it useful for other projects using beads\n- Plugin/hook system for custom checks\n\n## Dependencies\n\n- bd-umbf: Namespace isolation for beads pollution (blocking for full solution)\n\n## Success Metrics\n\n- Fewer CI failures on first PR push\n- Reduced \"fix nix hash\" commits\n- Contributors report preflight caught issues before CI","status":"open","priority":2,"issue_type":"epic","created_at":"2025-12-13T18:01:39.587078-08:00","updated_at":"2025-12-13T18:01:39.587078-08:00","dependencies":[{"issue_id":"bd-lfak","depends_on_id":"bd-umbf","type":"blocks","created_at":"2025-12-13T18:01:46.059901-08:00","created_by":"daemon"}]}
{"id":"bd-lfak.1","title":"Scaffold bd preflight command with checklist output","status":"closed","priority":2,"issue_type":"task","assignee":"beads/polecats/amber","created_at":"2025-12-30T18:06:29.297254-08:00","created_by":"mayor","updated_at":"2025-12-30T18:11:15.884294-08:00","closed_at":"2025-12-30T18:11:15.884294-08:00","close_reason":"Implemented static checklist output. Command now shows PR readiness checks. --check and --fix flags documented for future phases.","dependencies":[{"issue_id":"bd-lfak.1","depends_on_id":"bd-lfak","type":"parent-child","created_at":"2025-12-30T18:06:29.297783-08:00","created_by":"mayor"}]}
{"id":"bd-lfak.2","title":"Implement --check flag with test runner","description":"## Summary\nImplement the `--check` flag to run `go test -short ./...` and report results.\n\n## Implementation Details\n\n### Location\nFile: `cmd/bd/preflight.go`\n\n### Changes Required\n\n1. **Add check execution logic** in `runPreflight()`:\n```go\nif check {\n runChecks(cmd) // New function\n return\n}\n```\n\n2. **Implement test runner**:\n```go\nfunc runTestCheck() CheckResult {\n cmd := exec.Command(\"go\", \"test\", \"-short\", \"./...\")\n output, err := cmd.CombinedOutput()\n return CheckResult{\n Name: \"tests\",\n Passed: err == nil,\n Output: string(output),\n Command: \"go test -short ./...\",\n }\n}\n```\n\n3. **Define CheckResult struct**:\n```go\ntype CheckResult struct {\n Name string\n Passed bool\n Output string\n Command string\n}\n```\n\n4. **Output format**:\n```\n$ bd preflight --check\n✓ Tests pass\n Command: go test -short ./...\n \n# On failure:\n✗ Tests fail\n Command: go test -short ./...\n Output: [truncated test output]\n```\n\n### Testing\n- Add tests in `cmd/bd/preflight_test.go`\n- Test with passing tests (this repo)\n- Test with intentionally failing test (mock or temp file)\n\n### Acceptance Criteria\n- [x] `--check` flag runs tests (not just prints message)\n- [x] Clear pass/fail output with ✓/✗ symbols\n- [x] Shows command being run\n- [x] Shows output on failure (truncated if long)\n- [x] Exits with non-zero code if tests fail\n- [x] Works with `--json` flag for programmatic use","status":"hooked","priority":2,"issue_type":"task","assignee":"beads/polecats/basalt","created_at":"2025-12-30T18:06:30.419315-08:00","created_by":"mayor","updated_at":"2025-12-30T22:13:39.341845-08:00","dependencies":[{"issue_id":"bd-lfak.2","depends_on_id":"bd-lfak","type":"parent-child","created_at":"2025-12-30T18:06:30.419875-08:00","created_by":"mayor"},{"issue_id":"bd-lfak.2","depends_on_id":"bd-lfak.1","type":"blocks","created_at":"2025-12-30T18:06:48.582603-08:00","created_by":"mayor"}]}
{"id":"bd-lfak.2","title":"Implement --check flag with test runner","description":"## Summary\nImplement the `--check` flag to run `go test -short ./...` and report results.\n\n## Implementation Details\n\n### Location\nFile: `cmd/bd/preflight.go`\n\n### Changes Required\n\n1. **Add check execution logic** in `runPreflight()`:\n```go\nif check {\n runChecks(cmd) // New function\n return\n}\n```\n\n2. **Implement test runner**:\n```go\nfunc runTestCheck() CheckResult {\n cmd := exec.Command(\"go\", \"test\", \"-short\", \"./...\")\n output, err := cmd.CombinedOutput()\n return CheckResult{\n Name: \"tests\",\n Passed: err == nil,\n Output: string(output),\n Command: \"go test -short ./...\",\n }\n}\n```\n\n3. **Define CheckResult struct**:\n```go\ntype CheckResult struct {\n Name string\n Passed bool\n Output string\n Command string\n}\n```\n\n4. **Output format**:\n```\n$ bd preflight --check\n✓ Tests pass\n Command: go test -short ./...\n \n# On failure:\n✗ Tests fail\n Command: go test -short ./...\n Output: [truncated test output]\n```\n\n### Testing\n- Add tests in `cmd/bd/preflight_test.go`\n- Test with passing tests (this repo)\n- Test with intentionally failing test (mock or temp file)\n\n### Acceptance Criteria\n- [x] `--check` flag runs tests (not just prints message)\n- [x] Clear pass/fail output with ✓/✗ symbols\n- [x] Shows command being run\n- [x] Shows output on failure (truncated if long)\n- [x] Exits with non-zero code if tests fail\n- [x] Works with `--json` flag for programmatic use","status":"closed","priority":2,"issue_type":"task","assignee":"beads/polecats/basalt","created_at":"2025-12-30T18:06:30.419315-08:00","created_by":"mayor","updated_at":"2025-12-30T22:20:06.159587-08:00","closed_at":"2025-12-30T22:20:06.159587-08:00","close_reason":"Implemented --check flag with test runner, JSON output, and truncated output handling","dependencies":[{"issue_id":"bd-lfak.2","depends_on_id":"bd-lfak","type":"parent-child","created_at":"2025-12-30T18:06:30.419875-08:00","created_by":"mayor"},{"issue_id":"bd-lfak.2","depends_on_id":"bd-lfak.1","type":"blocks","created_at":"2025-12-30T18:06:48.582603-08:00","created_by":"mayor"}]}
{"id":"bd-lfak.3","title":"Implement lint check (golangci-lint)","description":"## Summary\nAdd lint check using golangci-lint to the preflight --check mode.\n\n## Implementation Details\n\n### Location\nFile: `cmd/bd/preflight.go`\n\n### Changes Required\n\n1. **Implement lint checker**:\n```go\nfunc runLintCheck() CheckResult {\n // First check if golangci-lint is available\n if _, err := exec.LookPath(\"golangci-lint\"); err != nil {\n return CheckResult{\n Name: \"lint\",\n Passed: false,\n Output: \"golangci-lint not found in PATH\",\n Command: \"golangci-lint run ./...\",\n Skipped: true,\n }\n }\n \n cmd := exec.Command(\"golangci-lint\", \"run\", \"./...\")\n output, err := cmd.CombinedOutput()\n return CheckResult{\n Name: \"lint\",\n Passed: err == nil,\n Output: string(output),\n Command: \"golangci-lint run ./...\",\n }\n}\n```\n\n2. **Add Skipped field to CheckResult** (if not already added by bd-lfak.2):\n```go\ntype CheckResult struct {\n Name string\n Passed bool\n Output string\n Command string\n Skipped bool // Tool not available\n}\n```\n\n3. **Output format**:\n```\n$ bd preflight --check\n✓ Lint passes\n Command: golangci-lint run ./...\n\n# When tool missing:\n⚠ Lint skipped (golangci-lint not found)\n Install: go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest\n\n# On failure:\n✗ Lint fails\n Command: golangci-lint run ./...\n Output: [lint errors]\n```\n\n### Dependencies\n- Depends on bd-lfak.2 for CheckResult struct and runChecks() framework\n\n### Testing\n- Test with clean lint (this repo should pass)\n- Test with golangci-lint not in PATH (mock or temp PATH)\n- Test with lint errors (intentional bad code)\n\n### Notes\n- This repo has baseline warnings documented in docs/LINTING.md\n- golangci-lint respects .golangci.yml config if present\n\n### Acceptance Criteria\n- [x] Runs golangci-lint when --check flag is used\n- [x] Gracefully handles missing golangci-lint binary\n- [x] Shows clear pass/fail/skip output\n- [x] Shows lint errors on failure\n- [x] Works with --json flag","status":"open","priority":2,"issue_type":"task","created_at":"2025-12-30T18:06:31.445431-08:00","created_by":"mayor","updated_at":"2025-12-30T19:28:51.93608-08:00","dependencies":[{"issue_id":"bd-lfak.3","depends_on_id":"bd-lfak","type":"parent-child","created_at":"2025-12-30T18:06:31.447094-08:00","created_by":"mayor"},{"issue_id":"bd-lfak.3","depends_on_id":"bd-lfak.1","type":"blocks","created_at":"2025-12-30T18:06:48.602793-08:00","created_by":"mayor"},{"issue_id":"bd-lfak.3","depends_on_id":"bd-lfak.2","type":"blocks","created_at":"2025-12-30T19:31:30.950646-08:00","created_by":"beads/crew/emma"}]}
{"id":"bd-lfak.4","title":"Implement nix-hash staleness detection","description":"## Summary\nDetect when go.sum has changed but vendorHash in default.nix may be stale.\n\n## Implementation Details\n\n### Location\nFile: `cmd/bd/preflight.go`\n\n### Detection Logic\n\n**Tier 1 (Simple - implement this):**\nCheck if go.sum has uncommitted changes (staged or unstaged). If so, warn that vendorHash might need updating.\n\n```go\nfunc runNixHashCheck() CheckResult {\n // Check if go.sum has changes\n cmd := exec.Command(\"git\", \"diff\", \"--name-only\", \"HEAD\", \"--\", \"go.sum\")\n output, _ := cmd.Output()\n \n // Also check staged changes\n stagedCmd := exec.Command(\"git\", \"diff\", \"--name-only\", \"--cached\", \"--\", \"go.sum\")\n stagedOutput, _ := stagedCmd.Output()\n \n hasChanges := len(output) \u003e 0 || len(stagedOutput) \u003e 0\n \n if hasChanges {\n return CheckResult{\n Name: \"nix-hash\",\n Passed: false,\n Output: \"go.sum has changes - vendorHash in default.nix may need updating\",\n Command: \"git diff HEAD -- go.sum\",\n Warning: true, // Not a hard failure, just a warning\n }\n }\n \n return CheckResult{\n Name: \"nix-hash\",\n Passed: true,\n Output: \"go.sum unchanged\",\n Command: \"git diff HEAD -- go.sum\",\n }\n}\n```\n\n**Tier 2 (Future - auto-fix):**\nIf nix is available, compute the correct vendorHash:\n```bash\nnix-prefetch-url --unpack \"https://...\"\n# or use nix build with --print-out-paths\n```\n\n### Key Files\n- `go.sum` - Go module checksums\n- `default.nix` - Contains vendorHash on line 12\n\n### Output Format\n```\n$ bd preflight --check\n✓ Nix hash current (go.sum unchanged)\n\n# When go.sum changed:\n⚠ Nix hash may be stale\n go.sum has uncommitted changes\n Hint: If you modified dependencies, run nix build to get new vendorHash\n \n# When nix available (future):\n✗ Nix hash stale\n Expected: sha256-KRR6dXzsSw8OmEHGBEVDBOoIgfoZ2p0541T9ayjGHlI=\n Current: sha256-ovG0EWQFtifHF5leEQTFvTjGvc+yiAjpAaqaV0OklgE=\n Fix: bd preflight --fix\n```\n\n### Add Warning field to CheckResult\n```go\ntype CheckResult struct {\n Name string\n Passed bool\n Output string\n Command string\n Skipped bool\n Warning bool // Yellow ⚠ instead of red ✗\n}\n```\n\n### Testing\n- Test with clean go.sum (no changes)\n- Test with modified go.sum (stage a fake change, then reset)\n- Test output format\n\n### Acceptance Criteria\n- [x] Detects when go.sum has uncommitted changes\n- [x] Shows as warning (⚠) not error (✗)\n- [x] Provides helpful hint about vendorHash\n- [x] Works with --json flag\n- [x] Does not require nix to be installed (just git)","status":"open","priority":2,"issue_type":"task","created_at":"2025-12-30T18:06:32.318167-08:00","created_by":"mayor","updated_at":"2025-12-30T19:29:29.995126-08:00","dependencies":[{"issue_id":"bd-lfak.4","depends_on_id":"bd-lfak","type":"parent-child","created_at":"2025-12-30T18:06:32.31998-08:00","created_by":"mayor"},{"issue_id":"bd-lfak.4","depends_on_id":"bd-lfak.1","type":"blocks","created_at":"2025-12-30T18:06:48.621655-08:00","created_by":"mayor"},{"issue_id":"bd-lfak.4","depends_on_id":"bd-lfak.2","type":"blocks","created_at":"2025-12-30T19:31:30.9704-08:00","created_by":"beads/crew/emma"}]}
{"id":"bd-lfak.5","title":"Implement version-sync check (version.go vs default.nix)","description":"## Summary\nCheck that version in `cmd/bd/version.go` matches version in `default.nix`.\n\n## Current State (as of writing)\n- version.go: Version = \"0.41.0\"\n- default.nix: version = \"0.37.0\"\n- **These are already out of sync!** This check would catch this.\n\n## Implementation Details\n\n### Location\nFile: `cmd/bd/preflight.go`\n\n### Key Files\n- `cmd/bd/version.go` line 17: `Version = \"0.41.0\"`\n- `default.nix` line 4: `version = \"0.37.0\";`\n\n### Implementation\n\n```go\nfunc runVersionSyncCheck() CheckResult {\n // Read version.go\n versionGoContent, err := os.ReadFile(\"cmd/bd/version.go\")\n if err != nil {\n return CheckResult{\n Name: \"version-sync\",\n Passed: false,\n Output: fmt.Sprintf(\"Cannot read cmd/bd/version.go: %v\", err),\n Skipped: true,\n }\n }\n \n // Extract version from version.go\n // Pattern: Version = \"X.Y.Z\"\n versionGoRe := regexp.MustCompile(`Version\\s*=\\s*\"([^\"]+)\"`)\n versionGoMatch := versionGoRe.FindSubmatch(versionGoContent)\n if versionGoMatch == nil {\n return CheckResult{\n Name: \"version-sync\",\n Passed: false,\n Output: \"Cannot parse version from version.go\",\n Skipped: true,\n }\n }\n goVersion := string(versionGoMatch[1])\n \n // Read default.nix\n nixContent, err := os.ReadFile(\"default.nix\")\n if err != nil {\n return CheckResult{\n Name: \"version-sync\",\n Passed: true, // No nix file = no sync needed\n Output: \"default.nix not found (skipping nix version check)\",\n Skipped: true,\n }\n }\n \n // Extract version from default.nix\n // Pattern: version = \"X.Y.Z\";\n nixRe := regexp.MustCompile(`version\\s*=\\s*\"([^\"]+)\"`)\n nixMatch := nixRe.FindSubmatch(nixContent)\n if nixMatch == nil {\n return CheckResult{\n Name: \"version-sync\",\n Passed: false,\n Output: \"Cannot parse version from default.nix\",\n Skipped: true,\n }\n }\n nixVersion := string(nixMatch[1])\n \n if goVersion != nixVersion {\n return CheckResult{\n Name: \"version-sync\",\n Passed: false,\n Output: fmt.Sprintf(\"Version mismatch: version.go=%s, default.nix=%s\", goVersion, nixVersion),\n Command: \"Compare cmd/bd/version.go and default.nix\",\n }\n }\n \n return CheckResult{\n Name: \"version-sync\",\n Passed: true,\n Output: fmt.Sprintf(\"Versions match: %s\", goVersion),\n Command: \"Compare cmd/bd/version.go and default.nix\",\n }\n}\n```\n\n### Output Format\n```\n$ bd preflight --check\n✓ Version sync (0.41.0)\n\n# On mismatch:\n✗ Version mismatch\n version.go: 0.41.0\n default.nix: 0.37.0\n Fix: Update default.nix to match version.go\n```\n\n### Future: Auto-fix\nFor --fix mode, update default.nix automatically:\n```go\n// Replace version line in default.nix\nnewContent := nixRe.ReplaceAll(nixContent, \n []byte(fmt.Sprintf(`version = \"%s\"`, goVersion)))\nos.WriteFile(\"default.nix\", newContent, 0644)\n```\n\n### Testing\n- Test with matching versions\n- Test with mismatched versions (current state!)\n- Test with missing files\n\n### Acceptance Criteria\n- [x] Reads version from both files\n- [x] Compares and reports mismatch\n- [x] Shows both versions clearly on mismatch\n- [x] Works when default.nix is missing (skip gracefully)\n- [x] Works with --json flag","status":"open","priority":2,"issue_type":"task","created_at":"2025-12-30T18:06:33.380378-08:00","created_by":"mayor","updated_at":"2025-12-30T19:30:02.607687-08:00","dependencies":[{"issue_id":"bd-lfak.5","depends_on_id":"bd-lfak","type":"parent-child","created_at":"2025-12-30T18:06:33.382134-08:00","created_by":"mayor"},{"issue_id":"bd-lfak.5","depends_on_id":"bd-lfak.1","type":"blocks","created_at":"2025-12-30T18:06:48.64101-08:00","created_by":"mayor"},{"issue_id":"bd-lfak.5","depends_on_id":"bd-lfak.2","type":"blocks","created_at":"2025-12-30T19:31:30.989707-08:00","created_by":"beads/crew/emma"}]}