woods 1.6.1 → 2.0.0.beta2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +2035 -0
- data/CONTRIBUTING.md +253 -87
- data/README.md +161 -513
- data/SECURITY.md +92 -0
- data/assets/woods-wordmark-white-with-bg.png +0 -0
- data/docs/AGENT_GUIDE.md +204 -0
- data/docs/AGENT_SETUP.md +205 -0
- data/docs/BACKEND_MATRIX.md +470 -0
- data/docs/CONFIGURATION_REFERENCE.md +655 -0
- data/docs/CONSOLE_MCP_SETUP.md +829 -0
- data/docs/DOCKER_SETUP.md +454 -0
- data/docs/EMBEDDING_MODELS.md +136 -0
- data/docs/EVALUATION.md +91 -0
- data/docs/EXTRACTOR_REFERENCE.md +765 -0
- data/docs/FAQ.md +544 -0
- data/docs/GETTING_STARTED.md +183 -0
- data/docs/INCREMENTAL_EXTRACTION.md +455 -0
- data/docs/INTERNALS.md +418 -0
- data/docs/MCP_HTTP_TRANSPORT.md +144 -0
- data/docs/MCP_SERVERS.md +231 -0
- data/docs/MCP_TOOL_COOKBOOK.md +987 -0
- data/docs/MCP_WORKTREE_SETUP.md +127 -0
- data/docs/NOTION_INTEGRATION.md +283 -0
- data/docs/OBSIDIAN_INTEGRATION.md +170 -0
- data/docs/PUBLISHED_INDEX.md +213 -0
- data/docs/README.md +94 -0
- data/docs/RETRIEVAL_GUIDE.md +267 -0
- data/docs/TOKEN_BENCHMARK.md +68 -0
- data/docs/TROUBLESHOOTING.md +841 -0
- data/docs/UNBLOCKED_INTEGRATION.md +279 -0
- data/docs/UPGRADING_TO_2.md +321 -0
- data/docs/WATCH_DAEMON.md +667 -0
- data/docs/WHY_WOODS.md +219 -0
- data/exe/woods-console +40 -4
- data/exe/woods-console-mcp +21 -35
- data/exe/woods-mcp +20 -7
- data/exe/woods-mcp-http +80 -11
- data/exe/woods-mcp-start +57 -52
- data/lib/generators/woods/install_generator.rb +6 -5
- data/lib/generators/woods/pgvector_generator.rb +6 -3
- data/lib/generators/woods/templates/add_pgvector_to_woods.rb.erb +29 -9
- data/lib/generators/woods/templates/create_woods_tables.rb.erb +5 -1
- data/lib/generators/woods/templates/woods.rb.tt +49 -28
- data/lib/tasks/woods.rake +622 -168
- data/lib/tasks/woods_checks.rake +107 -0
- data/lib/tasks/woods_evaluation.rake +164 -80
- data/lib/woods/ast/call_site_extractor.rb +6 -15
- data/lib/woods/ast/method_extractor.rb +19 -9
- data/lib/woods/ast/parser.rb +54 -8
- data/lib/woods/atomic_file.rb +171 -2
- data/lib/woods/builder.rb +310 -22
- data/lib/woods/cache/cache_middleware.rb +7 -2
- data/lib/woods/cache/cache_store.rb +9 -1
- data/lib/woods/cache/solid_cache_store.rb +6 -4
- data/lib/woods/change_set.rb +88 -0
- data/lib/woods/checks/generation_resolution.rb +34 -0
- data/lib/woods/checks/moved_messages.rb +186 -0
- data/lib/woods/chunking/semantic_chunker.rb +160 -18
- data/lib/woods/console/audit_logger.rb +12 -3
- data/lib/woods/console/bridge_protocol.rb +3 -16
- data/lib/woods/console/connection_manager.rb +51 -136
- data/lib/woods/console/dispatch_pipeline.rb +42 -12
- data/lib/woods/console/embedded_executor.rb +806 -149
- data/lib/woods/console/eval_guard.rb +27 -20
- data/lib/woods/console/input_contract.rb +78 -0
- data/lib/woods/console/model_validator.rb +29 -1
- data/lib/woods/console/rack_middleware.rb +65 -42
- data/lib/woods/console/redactor.rb +26 -8
- data/lib/woods/console/safe_context.rb +58 -10
- data/lib/woods/console/scope_predicate_parser.rb +41 -0
- data/lib/woods/console/server.rb +119 -247
- data/lib/woods/console/sql_noise_stripper.rb +125 -16
- data/lib/woods/console/sql_table_scanner.rb +82 -22
- data/lib/woods/console/sql_validator.rb +459 -29
- data/lib/woods/console/table_gate.rb +2 -2
- data/lib/woods/console/tool_specs.rb +463 -90
- data/lib/woods/console/tools/tier1.rb +1 -5
- data/lib/woods/console/tools/tier4.rb +18 -9
- data/lib/woods/coordination/lock_heartbeat.rb +103 -0
- data/lib/woods/coordination/pipeline_lock.rb +263 -53
- data/lib/woods/db/migrations/007_typed_snapshot_units.rb +45 -0
- data/lib/woods/db/migrator.rb +3 -9
- data/lib/woods/db/schema_version.rb +47 -2
- data/lib/woods/dependency_graph.rb +898 -64
- data/lib/woods/embedding/fake.rb +138 -0
- data/lib/woods/embedding/indexer.rb +832 -40
- data/lib/woods/embedding/openai.rb +77 -19
- data/lib/woods/embedding/provider.rb +189 -11
- data/lib/woods/embedding/text_preparer.rb +1 -1
- data/lib/woods/embedding/token_counter.rb +0 -7
- data/lib/woods/evaluation/ablation_agent_payload.rb +38 -0
- data/lib/woods/evaluation/ablation_executor.rb +67 -0
- data/lib/woods/evaluation/ablation_provenance.rb +38 -0
- data/lib/woods/evaluation/ablation_report_writer.rb +43 -0
- data/lib/woods/evaluation/ablation_runner.rb +173 -0
- data/lib/woods/evaluation/ablation_summary.rb +65 -0
- data/lib/woods/evaluation/ablation_task.rb +66 -0
- data/lib/woods/evaluation/ablation_task_set.rb +77 -0
- data/lib/woods/evaluation/ablation_timed_executor.rb +91 -0
- data/lib/woods/evaluation/ablation_worktree.rb +71 -0
- data/lib/woods/evaluation/baseline.rb +60 -0
- data/lib/woods/evaluation/baseline_runner.rb +11 -3
- data/lib/woods/evaluation/evaluator.rb +41 -8
- data/lib/woods/evaluation/query_set.rb +79 -13
- data/lib/woods/evaluation/report_generator.rb +20 -1
- data/lib/woods/export/unit_facts.rb +0 -11
- data/lib/woods/extracted_unit.rb +22 -63
- data/lib/woods/extractor.rb +2783 -238
- data/lib/woods/extractors/action_cable_extractor.rb +9 -4
- data/lib/woods/extractors/ast_source_extraction.rb +20 -2
- data/lib/woods/extractors/caching_extractor.rb +46 -12
- data/lib/woods/extractors/callback_analyzer.rb +39 -9
- data/lib/woods/extractors/component_discovery.rb +123 -0
- data/lib/woods/extractors/concern_extractor.rb +17 -3
- data/lib/woods/extractors/controller_extractor.rb +389 -29
- data/lib/woods/extractors/decorator_extractor.rb +7 -14
- data/lib/woods/extractors/engine_extractor.rb +53 -8
- data/lib/woods/extractors/event_extractor.rb +55 -4
- data/lib/woods/extractors/factory_extractor.rb +49 -11
- data/lib/woods/extractors/graphql_extractor.rb +162 -66
- data/lib/woods/extractors/i18n_extractor.rb +6 -1
- data/lib/woods/extractors/job_extractor.rb +51 -21
- data/lib/woods/extractors/lib_extractor.rb +23 -17
- data/lib/woods/extractors/line_neutralizer.rb +171 -0
- data/lib/woods/extractors/mailer_extractor.rb +9 -1
- data/lib/woods/extractors/manager_extractor.rb +19 -2
- data/lib/woods/extractors/migration_extractor.rb +22 -11
- data/lib/woods/extractors/model_extractor.rb +292 -57
- data/lib/woods/extractors/package_extractor.rb +154 -0
- data/lib/woods/extractors/phlex_extractor.rb +18 -3
- data/lib/woods/extractors/policy_extractor.rb +6 -5
- data/lib/woods/extractors/poro_extractor.rb +13 -14
- data/lib/woods/extractors/pundit_extractor.rb +3 -3
- data/lib/woods/extractors/rails_source_extractor.rb +24 -7
- data/lib/woods/extractors/rake_task_extractor.rb +158 -30
- data/lib/woods/extractors/reference_patterns.rb +38 -0
- data/lib/woods/extractors/route_extractor.rb +58 -2
- data/lib/woods/extractors/scheduled_job_extractor.rb +51 -35
- data/lib/woods/extractors/serializer_extractor.rb +3 -4
- data/lib/woods/extractors/service_extractor.rb +11 -1
- data/lib/woods/extractors/shared_dependency_scanner.rb +24 -34
- data/lib/woods/extractors/shared_utility_methods.rb +36 -6
- data/lib/woods/extractors/source_nesting.rb +560 -0
- data/lib/woods/extractors/state_machine_extractor.rb +30 -18
- data/lib/woods/extractors/test_mapping_extractor.rb +26 -9
- data/lib/woods/extractors/view_component_extractor.rb +28 -3
- data/lib/woods/extractors/view_engines/erb.rb +17 -3
- data/lib/woods/feedback/gap_detector.rb +9 -3
- data/lib/woods/feedback/store.rb +7 -1
- data/lib/woods/filename_utils.rb +29 -1
- data/lib/woods/flow_analysis/operation_extractor.rb +22 -10
- data/lib/woods/flow_assembler.rb +147 -26
- data/lib/woods/flow_document.rb +1 -0
- data/lib/woods/flow_precomputer.rb +175 -22
- data/lib/woods/gem_mapper.rb +285 -0
- data/lib/woods/generation.rb +185 -0
- data/lib/woods/git_command.rb +38 -0
- data/lib/woods/git_provenance.rb +16 -2
- data/lib/woods/graph_analyzer.rb +564 -87
- data/lib/woods/index_artifact.rb +93 -23
- data/lib/woods/mcp/bearer_auth.rb +102 -13
- data/lib/woods/mcp/bootstrap_state.rb +77 -0
- data/lib/woods/mcp/bootstrapper.rb +582 -77
- data/lib/woods/mcp/config_resolver.rb +66 -6
- data/lib/woods/mcp/errors.rb +60 -0
- data/lib/woods/mcp/index_reader.rb +836 -117
- data/lib/woods/mcp/index_reader_pinning.rb +78 -0
- data/lib/woods/mcp/origin_guard.rb +66 -7
- data/lib/woods/mcp/protocol_policy.rb +98 -0
- data/lib/woods/mcp/provider_probe.rb +45 -6
- data/lib/woods/mcp/renderers/markdown_renderer.rb +72 -4
- data/lib/woods/mcp/renderers/plain_renderer.rb +54 -6
- data/lib/woods/mcp/server.rb +898 -152
- data/lib/woods/mcp/tasks/extension.rb +196 -0
- data/lib/woods/mcp/tasks/request_capture.rb +45 -0
- data/lib/woods/mcp/tasks/store.rb +518 -0
- data/lib/woods/mcp/tool_contract.rb +171 -0
- data/lib/woods/mcp/tool_response_renderer.rb +7 -0
- data/lib/woods/model_name_cache.rb +19 -1
- data/lib/woods/notion/client.rb +132 -36
- data/lib/woods/notion/exporter.rb +456 -61
- data/lib/woods/notion/mappers/column_mapper.rb +34 -5
- data/lib/woods/notion/mappers/migration_mapper.rb +32 -8
- data/lib/woods/notion/mappers/model_mapper.rb +21 -6
- data/lib/woods/notion/mappers/shared.rb +45 -3
- data/lib/woods/notion/sync_manifest.rb +258 -0
- data/lib/woods/obsidian/errors.rb +6 -0
- data/lib/woods/obsidian/name_mapper.rb +40 -24
- data/lib/woods/obsidian/vault_exporter.rb +103 -36
- data/lib/woods/operator/pipeline_guard.rb +118 -21
- data/lib/woods/operator/status_reporter.rb +20 -3
- data/lib/woods/path_dispatcher.rb +276 -0
- data/lib/woods/payload_store.rb +236 -0
- data/lib/woods/published_index/edge_shaper.rb +61 -0
- data/lib/woods/published_index/generation_catalog.rb +72 -0
- data/lib/woods/published_index/typed_unit_reader.rb +48 -0
- data/lib/woods/published_index.rb +287 -0
- data/lib/woods/railtie.rb +69 -30
- data/lib/woods/railtie_support.rb +167 -0
- data/lib/woods/release.rb +12 -0
- data/lib/woods/reload_policy.rb +206 -0
- data/lib/woods/resilience/circuit_breaker.rb +47 -8
- data/lib/woods/resilience/index_validator.rb +296 -10
- data/lib/woods/resilience/retryable_provider.rb +71 -6
- data/lib/woods/resolved_config.rb +55 -11
- data/lib/woods/retrieval/context_assembler.rb +132 -40
- data/lib/woods/retrieval/query_classifier.rb +26 -8
- data/lib/woods/retrieval/ranker.rb +193 -28
- data/lib/woods/retrieval/search_executor.rb +206 -39
- data/lib/woods/retriever.rb +317 -71
- data/lib/woods/retry_after.rb +22 -2
- data/lib/woods/ruby_analyzer/class_analyzer.rb +10 -14
- data/lib/woods/ruby_analyzer/fqn_builder.rb +2 -0
- data/lib/woods/ruby_analyzer/mermaid_renderer.rb +14 -4
- data/lib/woods/ruby_analyzer/method_analyzer.rb +1 -1
- data/lib/woods/ruby_analyzer/trace_enricher.rb +3 -0
- data/lib/woods/ruby_analyzer.rb +21 -5
- data/lib/woods/session_tracer/file_store.rb +138 -19
- data/lib/woods/session_tracer/middleware.rb +1 -2
- data/lib/woods/session_tracer/redis_store.rb +122 -12
- data/lib/woods/session_tracer/session_flow_assembler.rb +57 -17
- data/lib/woods/session_tracer/session_flow_document.rb +56 -14
- data/lib/woods/session_tracer/solid_cache_coordination.rb +192 -0
- data/lib/woods/session_tracer/solid_cache_store.rb +560 -91
- data/lib/woods/session_tracer/store.rb +14 -1
- data/lib/woods/storage/metadata_store.rb +230 -26
- data/lib/woods/storage/pgvector.rb +180 -22
- data/lib/woods/storage/qdrant.rb +367 -41
- data/lib/woods/storage/snapshotter/metadata.rb +79 -16
- data/lib/woods/storage/snapshotter/vector.rb +128 -17
- data/lib/woods/storage/snapshotter.rb +23 -5
- data/lib/woods/storage/vector_store.rb +49 -8
- data/lib/woods/storage_identity.rb +28 -0
- data/lib/woods/tasks.rb +53 -2
- data/lib/woods/temporal/json_snapshot_store.rb +112 -42
- data/lib/woods/temporal/snapshot_store.rb +139 -42
- data/lib/woods/unblocked/client.rb +119 -17
- data/lib/woods/unblocked/document_builder.rb +34 -2
- data/lib/woods/unblocked/exporter.rb +63 -27
- data/lib/woods/unblocked/rate_limiter.rb +23 -9
- data/lib/woods/unblocked/sync_manifest.rb +16 -8
- data/lib/woods/update_check.rb +24 -1
- data/lib/woods/util/uuid5.rb +124 -0
- data/lib/woods/version.rb +1 -1
- data/lib/woods/watch/daemon.rb +1345 -0
- data/lib/woods/watch/listen_watcher.rb +81 -0
- data/lib/woods/watch/polling_watcher.rb +137 -0
- data/lib/woods/watch/status.rb +169 -0
- data/lib/woods/watch/tree_scan.rb +163 -0
- data/lib/woods/watch/watcher.rb +100 -0
- data/lib/woods.rb +138 -9
- data/plugin/.claude-plugin/plugin.json +18 -0
- data/plugin/hooks/hooks.json +29 -0
- data/plugin/hooks/woods-post-edit.sh +226 -0
- data/plugin/hooks/woods-session-start.sh +77 -0
- data/plugin/skills/woods-agent-enable/SKILL.md +51 -0
- data/plugin/skills/woods-diagnose/SKILL.md +75 -0
- data/plugin/skills/woods-investigate/SKILL.md +39 -0
- data/plugin/skills/woods-mcp-config/SKILL.md +101 -0
- data/plugin/skills/woods-setup/SKILL.md +99 -0
- metadata +134 -23
- data/lib/woods/console/adapters/cache_adapter.rb +0 -58
- data/lib/woods/console/adapters/good_job_adapter.rb +0 -33
- data/lib/woods/console/adapters/job_adapter.rb +0 -74
- data/lib/woods/console/adapters/sidekiq_adapter.rb +0 -33
- data/lib/woods/console/adapters/solid_queue_adapter.rb +0 -33
- data/lib/woods/console/bridge.rb +0 -210
- data/lib/woods/formatting/claude_adapter.rb +0 -98
- data/lib/woods/formatting/generic_adapter.rb +0 -56
- data/lib/woods/formatting/gpt_adapter.rb +0 -64
- data/lib/woods/notion/mapper.rb +0 -40
- data/lib/woods/observability/health_check.rb +0 -79
- data/lib/woods/observability/instrumentation.rb +0 -34
data/CONTRIBUTING.md
CHANGED
|
@@ -1,127 +1,293 @@
|
|
|
1
1
|
# Contributing to Woods
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<!-- release-state:contributing-intro -->
|
|
4
|
+
Woods welcomes bug fixes, extractor coverage, storage and retrieval improvements, MCP compatibility work, documentation, and focused performance changes. This guide covers the shared contribution contract. Coding agents working from a source checkout should also read the repository's [AGENTS.md](https://github.com/lost-in-the/woods/blob/v2.0.0.beta2/AGENTS.md).
|
|
5
|
+
<!-- release-state:end -->
|
|
4
6
|
|
|
5
|
-
##
|
|
7
|
+
## Choose the right channel
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
- **Bug:** open an issue with reproduction steps, expected and actual behavior, Woods/Ruby/Rails versions, database adapter, and the smallest useful log or stack trace.
|
|
10
|
+
- **Feature:** describe the user problem, intended outcome, alternatives considered, and affected extraction/MCP/storage surfaces.
|
|
11
|
+
- **Security issue:** do not open a public issue. Follow [SECURITY.md](SECURITY.md).
|
|
12
|
+
- **Question or documentation gap:** open an issue and point to the page or workflow that was unclear.
|
|
8
13
|
|
|
9
|
-
|
|
10
|
-
- Steps to reproduce
|
|
11
|
-
- Expected vs. actual behavior
|
|
12
|
-
- Your Ruby version, Rails version, and database adapter
|
|
14
|
+
Search existing issues and pull requests first. A minimal reproduction in a small Rails app is more useful than a large application dump; never attach secrets or production data.
|
|
13
15
|
|
|
14
|
-
##
|
|
16
|
+
## Development setup
|
|
15
17
|
|
|
16
|
-
|
|
18
|
+
Prerequisites are Git, Ruby 3.0 or later, and a Bundler version compatible with that Ruby. The repository tests several Ruby versions and intentionally does not pin one local version; select a supported Ruby with your normal version manager, then confirm `ruby --version` and `bundle --version`. `bin/setup` installs the bundle but does not install or select Ruby.
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
```bash
|
|
21
|
+
git clone https://github.com/lost-in-the/woods.git
|
|
22
|
+
cd woods
|
|
23
|
+
bin/setup
|
|
24
|
+
bin/rake spec
|
|
25
|
+
bin/rubocop
|
|
26
|
+
```
|
|
23
27
|
|
|
24
|
-
|
|
25
|
-
2. Install dependencies: `bin/setup`
|
|
26
|
-
3. Make your changes
|
|
27
|
-
4. Add tests for new functionality
|
|
28
|
-
5. Ensure the test suite passes: `bundle exec rake spec`
|
|
29
|
-
6. Ensure code style passes: `bundle exec rubocop`
|
|
30
|
-
7. Update CHANGELOG.md with your changes
|
|
31
|
-
8. Complete the **Pre-PR requirements** below
|
|
32
|
-
9. Open a pull request
|
|
28
|
+
`Gemfile.lock` is gitignored, so a fresh worktree (as opposed to a clone) needs it copied in from an existing checkout before running any `bin/*` command.
|
|
33
29
|
|
|
34
|
-
|
|
30
|
+
Create a branch from current `main`. Keep each pull request to one logical change and preserve unrelated formatting and refactors for separate work.
|
|
35
31
|
|
|
36
|
-
|
|
32
|
+
`main` is the development branch: it holds work for the next release and can run ahead of the latest published gem. Releases are cut from version tags by the guarded workflow in the [release section below](#release-flow); documentation matching a published gem lives on that release's tag.
|
|
37
33
|
|
|
38
|
-
|
|
39
|
-
`plugin/skills/` user guides, `CHANGELOG.md` — must be updated in the *same* PR. Don't ship
|
|
40
|
-
behavior the docs still describe the old way.
|
|
41
|
-
2. **Investigate plugin-functionality impact.** If the change touches anything the distributed
|
|
42
|
-
user skills rely on — a rake task, MCP tool or its arguments, an executable (`woods-mcp`,
|
|
43
|
-
`woods-mcp-start`, `woods-console-mcp`, `woods-mcp-http`), a config key, or setup steps —
|
|
44
|
-
investigate whether `plugin/skills/{woods-setup,woods-mcp-config,woods-diagnose}` need to
|
|
45
|
-
change.
|
|
34
|
+
## Understand the repository
|
|
46
35
|
|
|
47
|
-
|
|
36
|
+
| Path | Responsibility |
|
|
37
|
+
|---|---|
|
|
38
|
+
| `lib/woods/extractor.rb`, `lib/woods/extractors/` | Runtime Rails extraction pipeline and extractors |
|
|
39
|
+
| `lib/woods/mcp/` | Read-only Index MCP server and protocol behavior |
|
|
40
|
+
| `lib/woods/console/` | Live Rails Console MCP and safeguards |
|
|
41
|
+
| `lib/woods/storage/`, `lib/woods/embedding/`, `lib/woods/retrieval/` | Persistence, vectors, and semantic retrieval |
|
|
42
|
+
| `lib/tasks/` | Rails/Rake operational interface |
|
|
43
|
+
| `spec/` | Unit, contract, and opt-in integration specs |
|
|
44
|
+
| `spec/dummy/` | Booted Rails fixture application |
|
|
45
|
+
| `docs/` | User, agent, operational, and reference documentation |
|
|
46
|
+
| `plugin/skills/` | Distributed Woods skills (setup/upgrade, MCP configuration, investigation, agent enablement, diagnosis) |
|
|
48
47
|
|
|
49
|
-
|
|
50
|
-
[
|
|
51
|
-
|
|
48
|
+
<!-- release-state:contributing-architecture -->
|
|
49
|
+
Read [CLAUDE.md](https://github.com/lost-in-the/woods/blob/v2.0.0.beta2/CLAUDE.md) for architecture and implementation gotchas before changing runtime behavior.
|
|
50
|
+
<!-- release-state:end -->
|
|
52
51
|
|
|
53
|
-
|
|
54
|
-
documents, **update the skill in the same PR**.
|
|
55
|
-
- The skills carry a Version Preflight (operate only against the installed version). **Land the
|
|
56
|
-
skill change with the release that ships the capability** — never document a feature in a
|
|
57
|
-
skill before the version that provides it is released. Bump `plugin/.claude-plugin/plugin.json`
|
|
58
|
-
`version` when the skill content changes.
|
|
59
|
-
- If the change requires a new marketplace entry, `ref` pin, or metadata edit, open a **paired
|
|
60
|
-
PR against `lost-in-the/plugins`** and link it from this PR.
|
|
52
|
+
### Agent orientation and static self-map
|
|
61
53
|
|
|
62
|
-
|
|
54
|
+
When investigating Woods itself, agents can create a disposable, MCP-queryable
|
|
55
|
+
map of the gem source before planning a broad change or debugging a cross-cutting
|
|
56
|
+
problem:
|
|
63
57
|
|
|
64
58
|
```bash
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
bundle exec rake spec # Run tests
|
|
69
|
-
bundle exec rubocop # Check style
|
|
59
|
+
output_dir="$(mktemp -d)"
|
|
60
|
+
bin/rake "woods:self_map[$output_dir]"
|
|
61
|
+
bundle exec woods-mcp-start "$output_dir"
|
|
70
62
|
```
|
|
71
63
|
|
|
72
|
-
|
|
64
|
+
This internal developer task publishes an atomic standard index generation.
|
|
65
|
+
Use `woods_status`, `structure`, `search`, `lookup`, `dependencies`, and
|
|
66
|
+
`dependents` to identify ownership and estimate the static blast radius. The
|
|
67
|
+
map is Woods-only, has no embeddings, and must remain out of version control.
|
|
68
|
+
It is not a replacement for booted Rails extraction or evidence of runtime
|
|
69
|
+
Rails behavior; use the normal host-app pipeline for that.
|
|
73
70
|
|
|
74
|
-
|
|
71
|
+
## Make the change
|
|
72
|
+
|
|
73
|
+
1. Reproduce a bug or define the expected behavior.
|
|
74
|
+
2. Add or update the smallest test that can fail for the behavior.
|
|
75
|
+
3. Make the targeted implementation change.
|
|
76
|
+
4. Run the narrow test, then the relevant broader suite.
|
|
77
|
+
5. Update the canonical documentation, plugin skill, and changelog when the public contract changes.
|
|
78
|
+
6. Review the complete diff before opening a pull request.
|
|
79
|
+
|
|
80
|
+
Woods extracts Rails behavior through a booted runtime. Features that depend on routes, Active Record reflections, descendants, or framework internals must use runtime introspection. Unit tests may isolate collaborators, but version-sensitive behavior also needs the booted-app lane.
|
|
81
|
+
|
|
82
|
+
## Validate in proportion to the change
|
|
83
|
+
|
|
84
|
+
Start with the smallest command that exercises your work:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# One spec file
|
|
88
|
+
bin/rspec spec/path/to/spec.rb
|
|
89
|
+
|
|
90
|
+
# Unit/contract suite (booted-app and live-backend lanes excluded)
|
|
91
|
+
bin/rake spec
|
|
92
|
+
|
|
93
|
+
# Style
|
|
94
|
+
bin/rubocop
|
|
95
|
+
```
|
|
75
96
|
|
|
76
|
-
|
|
77
|
-
- **Integration specs**: Run inside a host Rails app to test real extraction.
|
|
97
|
+
Before requesting review, run the full unit suite and style check unless the PR explains why one cannot run.
|
|
78
98
|
|
|
79
|
-
|
|
99
|
+
Coverage from the default process excludes opt-in Rails, installed-artifact, and live-backend lanes. Report their results separately; a low percentage for subprocess-driven tasks does not establish that they are untested. CI enforces the aggregate line floor and measures branches, but does not enforce a branch floor. Add behavior-based regressions and real optional-gem fixtures for changed extraction paths before proposing higher thresholds.
|
|
80
100
|
|
|
81
101
|
### Rails version matrix
|
|
82
102
|
|
|
83
|
-
The gem supports
|
|
103
|
+
The gem supports Ruby 3.0 or later and Rails 6.0 through 8.x. CI separates fast unit coverage from real Rails boots:
|
|
84
104
|
|
|
85
|
-
-
|
|
86
|
-
|
|
87
|
-
Gemfile rather than per Rails version.
|
|
88
|
-
- The `rails-matrix` job runs the **booted-app extraction test**
|
|
89
|
-
(`spec/integration/booted_extraction_spec.rb` against `spec/dummy`) under each
|
|
90
|
-
supported Rails — 6.0, 6.1, 7.0, 7.1, 7.2, 8.0 — using per-version gemfiles
|
|
91
|
-
under `gemfiles/`. This is the version-sensitive gate: it boots a real Rails
|
|
92
|
-
app in-process and runs an extraction. (The booted spec is tagged `:booted_app`
|
|
93
|
-
and excluded from the default `rake spec`; `WOODS_RUN_BOOTED_APP=1` opts it in,
|
|
94
|
-
and it must run in its own process — it can't share one with the unit suite.)
|
|
105
|
+
- the base test job runs unit specs across supported Ruby versions;
|
|
106
|
+
- the `rails-matrix` job boots `spec/dummy` and performs extraction for each supported Rails line using `gemfiles/rails_*.gemfile`.
|
|
95
107
|
|
|
96
|
-
|
|
97
|
-
(`eval_gemfile`-ing the base `Gemfile` and pinning Rails) because Appraisal can't
|
|
98
|
-
generate from the conditional base Gemfile. To run a single Rails row locally:
|
|
108
|
+
Run one Rails row locally:
|
|
99
109
|
|
|
100
110
|
```bash
|
|
101
111
|
BUNDLE_GEMFILE=gemfiles/rails_7.2.gemfile bundle install
|
|
102
112
|
WOODS_RUN_BOOTED_APP=1 BUNDLE_GEMFILE=gemfiles/rails_7.2.gemfile \
|
|
103
|
-
|
|
113
|
+
bin/rspec spec/integration/booted_extraction_spec.rb
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
When adding a Rails line, update `Appraisals`, the corresponding hand-maintained gemfile, and `.github/workflows/ci.yml`. For Rails below 7.1, copy an existing 6.x gemfile so its sqlite3 and concurrent-ruby compatibility pins are preserved.
|
|
117
|
+
|
|
118
|
+
### Live storage and SQL dialects
|
|
119
|
+
|
|
120
|
+
The opt-in `live-backends` lane verifies behavior against PostgreSQL/pgvector and Qdrant that doubles cannot prove, including batch conflicts, delete addressing, filter translation, and extension setup.
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
BUNDLE_GEMFILE=gemfiles/live_backends.gemfile bundle install
|
|
124
|
+
WOODS_RUN_LIVE_BACKENDS=1 BUNDLE_GEMFILE=gemfiles/live_backends.gemfile \
|
|
125
|
+
bin/rspec spec/integration/live_backends_spec.rb spec/integration/console_sql_dialects_spec.rb
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
The lane expects reachable PostgreSQL/pgvector, MySQL, and Qdrant services. Configure endpoints with `WOODS_PG_URL`, `WOODS_MYSQL_URL`, and `WOODS_QDRANT_URL`. The Console contracts exercise blocked-table enforcement and legitimate SQL on both database dialects. New adapter behavior that depends on a real server belongs in this lane.
|
|
129
|
+
|
|
130
|
+
## Keep public surfaces synchronized
|
|
131
|
+
|
|
132
|
+
A pull request is incomplete when behavior and user guidance disagree.
|
|
133
|
+
|
|
134
|
+
Update the canonical owner for any changed contract:
|
|
135
|
+
|
|
136
|
+
| Change | Documentation owner |
|
|
137
|
+
|---|---|
|
|
138
|
+
| Install or first run | `docs/GETTING_STARTED.md` |
|
|
139
|
+
| Agent-operated installation | `docs/AGENT_SETUP.md` |
|
|
140
|
+
| Configuration key/default | `docs/CONFIGURATION_REFERENCE.md` |
|
|
141
|
+
| MCP setup or registered tools | `docs/MCP_SERVERS.md` |
|
|
142
|
+
| Agent query workflow | `docs/AGENT_GUIDE.md` |
|
|
143
|
+
| Console security/transport | `docs/CONSOLE_MCP_SETUP.md` |
|
|
144
|
+
| Major-version behavior | `docs/UPGRADING_TO_2.md` |
|
|
145
|
+
| Failure diagnosis | `docs/TROUBLESHOOTING.md` |
|
|
146
|
+
|
|
147
|
+
If a rake task, executable, MCP tool/argument, config key, setup step, or diagnosis path changes, inspect all five distributed skills under `plugin/skills/`. Update affected skills in the same Woods PR and bump `plugin/.claude-plugin/plugin.json` when skill content changes.
|
|
148
|
+
|
|
149
|
+
The plugin is published through the [`lost-in-the/plugins`](https://github.com/lost-in-the/plugins) marketplace as a git-subdir reference. Open and cross-link a paired marketplace PR when compatibility metadata, the entry, or its ref must change. Skills must check the installed Woods version and must not document unreleased capabilities as available.
|
|
150
|
+
|
|
151
|
+
Update `CHANGELOG.md` for user-visible changes. Internal refactors and typo-only documentation fixes normally do not need an entry.
|
|
152
|
+
|
|
153
|
+
## Pull request evidence
|
|
154
|
+
|
|
155
|
+
Include:
|
|
156
|
+
|
|
157
|
+
- the problem and user-visible outcome;
|
|
158
|
+
- implementation scope and important tradeoffs;
|
|
159
|
+
- exact validation commands and results;
|
|
160
|
+
- Rails/storage lanes run or intentionally not run;
|
|
161
|
+
- public docs and plugin impact;
|
|
162
|
+
- migration, compatibility, security, and rollback notes when applicable;
|
|
163
|
+
- screenshots or transcript excerpts only when they materially verify behavior.
|
|
164
|
+
|
|
165
|
+
Do not use empty assertions or output-only tests. A regression test must fail before the fix and exercise the same runtime path as production behavior.
|
|
166
|
+
|
|
167
|
+
## Code conventions
|
|
168
|
+
|
|
169
|
+
- Add `# frozen_string_literal: true` to Ruby files.
|
|
170
|
+
- Document public APIs with YARD where it improves their contract.
|
|
171
|
+
- Rescue `StandardError` or a narrower class; never use a bare rescue.
|
|
172
|
+
- Extractors return `Array<Woods::ExtractedUnit>`.
|
|
173
|
+
- Keep MCP stdout free of non-protocol output.
|
|
174
|
+
- Prefer explicit structured errors over suppressing a failure.
|
|
175
|
+
|
|
176
|
+
By contributing, you agree that your contribution is licensed under the [MIT License](LICENSE.txt).
|
|
177
|
+
|
|
178
|
+
## Release flow
|
|
179
|
+
|
|
180
|
+
`main` is the development branch and never claims a released version. Between releases it carries the alpha development marker. Every release, including a beta or a release candidate, is an explicit commit plus a tag, cut by one rake task and published only by the guarded workflow.
|
|
181
|
+
|
|
182
|
+
| State | `Woods::VERSION` | Tagged | On RubyGems | Documentation links point at |
|
|
183
|
+
|---|---|---|---|---|
|
|
184
|
+
| Development | `X.Y.Z.alpha` | never | never | `main` |
|
|
185
|
+
| Beta | `X.Y.Z.betaN` | `vX.Y.Z.betaN` | prerelease | the tag |
|
|
186
|
+
| Release candidate | `X.Y.Z.rcN` | `vX.Y.Z.rcN` | prerelease | the tag |
|
|
187
|
+
| Release | `X.Y.Z` | `vX.Y.Z` | stable | the tag |
|
|
188
|
+
|
|
189
|
+
RubyGems treats any letter in a version as a prerelease, so a `~> 1.6` or `~> 2.0` constraint never resolves a beta or a release candidate. Adopting one is explicit: `gem "woods", "2.0.0.beta1"`.
|
|
190
|
+
|
|
191
|
+
`spec/release_v2/version_state_spec.rb` enforces this table on every commit. VERSION is either an alpha or the changelog carries its dated heading, and the four `release-state` documentation fences match the state VERSION declares.
|
|
192
|
+
|
|
193
|
+
### During feature work
|
|
194
|
+
|
|
195
|
+
- Do not edit `lib/woods/version.rb` by hand.
|
|
196
|
+
- Put changelog entries under `## [Unreleased]` only, beneath one of its `###` headings. Duplicate headings are merged at release time, in the order they first appear.
|
|
197
|
+
- Leave the `release-state` fences alone. `release:prepare` rewrites them.
|
|
198
|
+
|
|
199
|
+
### Preparing a release
|
|
200
|
+
|
|
201
|
+
One command per transition. It never commits, tags, pushes, or publishes.
|
|
202
|
+
|
|
203
|
+
| Transition | Command |
|
|
204
|
+
|---|---|
|
|
205
|
+
| Alpha to the first beta | `bin/rake "release:prepare[2.0.0.beta1]"` |
|
|
206
|
+
| Beta to the next beta or a release candidate | `bin/rake "release:prepare[2.0.0.rc1]"` |
|
|
207
|
+
| Release candidate to the release | `bin/rake "release:prepare[2.0.0]"` |
|
|
208
|
+
| After the release publishes, reopen development | `bin/rake "release:reopen[2.1.0.alpha]"` |
|
|
209
|
+
|
|
210
|
+
`release:prepare` refuses a dirty working tree, a version that moves backwards, a version whose base is not the line `main` is developing, and an alpha target. It then bumps VERSION, folds `## [Unreleased]` into `## [<version>] - <date>` with one block per `###` heading, restates the fences, regenerates the surface inventory, and prints the tag and dispatch commands. Every rewrite is computed before any of it is written, so a refusal leaves the working tree untouched.
|
|
211
|
+
|
|
212
|
+
A final release also absorbs every prerelease section of its own base version. Cutting `2.0.0` folds `## [2.0.0.beta1]` and `## [2.0.0.rc1]` into `## [2.0.0] - <date>` and removes their headings, prerelease entries first and anything written after them second, so the notes a user reads for 2.0.0 are the whole story rather than three fragments. An empty `## [Unreleased]` is therefore legitimate for a final release cut straight from a release candidate. A beta or a release candidate has nothing to absorb, so an empty Unreleased section refuses: there is nothing new to publish.
|
|
213
|
+
|
|
214
|
+
Review the diff and run the release contracts:
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
bin/rspec spec/release_v2
|
|
218
|
+
bin/rake release_v2:verify_surface_inventory
|
|
219
|
+
bin/rspec spec/integration/packaged_gem_spec.rb
|
|
104
220
|
```
|
|
105
221
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
222
|
+
Then commit and open a pull request. The release commit lands on `main` through review like any other change.
|
|
223
|
+
|
|
224
|
+
### After the release commit merges
|
|
225
|
+
|
|
226
|
+
A release is pinned by its tag, never by a branch:
|
|
227
|
+
|
|
228
|
+
| Step | Command | What guards it |
|
|
229
|
+
|---|---|---|
|
|
230
|
+
| Tag the merge commit | `git tag v<version> <merge-sha> && git push origin v<version>` (lightweight or annotated both work) | `script/validate-release` requires the tag to sit on `main` history, match `Woods::VERSION`, match the dated `CHANGELOG.md` heading, and not be an alpha |
|
|
231
|
+
| Trigger the release workflow | `gh api --method POST repos/lost-in-the/woods/dispatches -f event_type=release -F 'client_payload[tag]=v<version>' -F 'client_payload[ci_run_id]=<id>'` where `<id>` is the green CI run on the tagged SHA (requires Contents write) | `.github/workflows/release.yml` re-validates the named CI run through the API, verifies the artifact digest, and runs secret-free candidate package tests before publishing |
|
|
232
|
+
| Verify publication | `gem info woods --remote` shows the new version; for a prerelease, `gem info woods --remote --prerelease`. The README gem badge updates on its own | just before pushing, the workflow re-runs `script/verify-release-tag` so a tag that moved since validation aborts the publish |
|
|
233
|
+
|
|
234
|
+
Nothing is published from a laptop: the workflow builds and pushes the gem from the validated CI artifact, so the bytes on RubyGems are the bytes CI tested. `rake release` and `rake release:rubygem_push`, which `bundler/gem_tasks` installs, are blocked for that reason.
|
|
235
|
+
|
|
236
|
+
After a final release publishes, reopen development with `release:reopen` in a follow-up pull request.
|
|
237
|
+
|
|
238
|
+
### When a dispatch fails
|
|
239
|
+
|
|
240
|
+
`release-context` and `publish` both check out `github.sha`, the default
|
|
241
|
+
branch's tip at dispatch time, not the tag: `release-context` re-validates the
|
|
242
|
+
named CI run, checks the live `release` environment, and runs
|
|
243
|
+
`script/validate-release`; `publish` runs `script/verify-release-tag` and
|
|
244
|
+
pushes the downloaded artifact. Only `package-test` checks out
|
|
245
|
+
`needs.release-context.outputs.release-sha`, the tag's own commit, because
|
|
246
|
+
that is what CI actually built and tested. The gem bytes `publish` pushes were
|
|
247
|
+
built by CI at `release-sha`; `publish` never rebuilds them.
|
|
113
248
|
|
|
114
|
-
|
|
249
|
+
That split decides the fix for a failed dispatch:
|
|
250
|
+
|
|
251
|
+
| What failed | Lives in | Fix |
|
|
252
|
+
|---|---|---|
|
|
253
|
+
| `script/validate-release-run`, `script/validate-release`, `script/verify-release-tag`, or the workflow files themselves | main, read at `github.sha` | merge the fix to main, then re-dispatch at the same tag; the tag never moves |
|
|
254
|
+
| Live `release` environment settings (protection rule, admin bypass) | GitHub environment configuration, not the tree | fix the setting directly; no commit or re-dispatch needed |
|
|
255
|
+
| Anything under `spec/` or `lib/` that `package-test` actually runs against the candidate | the tagged commit, read at `release-sha` | a main-only fix does not reach the candidate; merge it, then move the tag to the new main tip and get a fresh CI run on it |
|
|
256
|
+
|
|
257
|
+
Both failure classes happened in the beta1 dispatch: a `REQUIRED_CI_JOBS`
|
|
258
|
+
prefix left behind by a `ci.yml` job rename was a validator fix that needed
|
|
259
|
+
only a merge and a re-dispatch; two `packaged_gem_spec.rb` smoke failures
|
|
260
|
+
traced to hard-coded `2.0.0` literals needed the tag moved to the commit that
|
|
261
|
+
fixed them, because the candidate job runs the spec file at the tag.
|
|
262
|
+
|
|
263
|
+
**Moving a tag is acceptable only before publication.** Once `publish` has
|
|
264
|
+
pushed the gem to RubyGems, the tag is the permanent, immutable record of what
|
|
265
|
+
was published; move it before that point only, with
|
|
266
|
+
`git tag -f v<version> <new-sha> && git push --force origin v<version>` run by
|
|
267
|
+
the maintainer, followed by a fresh CI run on the new tag SHA before
|
|
268
|
+
re-dispatching.
|
|
269
|
+
|
|
270
|
+
### Publishing the GitHub Release entry
|
|
271
|
+
|
|
272
|
+
The workflow deliberately creates no GitHub Release: the API cannot bind an
|
|
273
|
+
existing tag to an expected commit atomically, so automating it would race the
|
|
274
|
+
tag's own verification. Once `gem info woods --remote` (or `--remote
|
|
275
|
+
--prerelease`) confirms publication, create the entry by hand:
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
gh release create v<version> --verify-tag --notes-file <file> # release
|
|
279
|
+
gh release create v<version> --verify-tag --prerelease --notes-file <file> # beta or rc
|
|
280
|
+
```
|
|
115
281
|
|
|
116
|
-
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
282
|
+
`--verify-tag` refuses if the tag is missing or moved. Write `<file>` as a
|
|
283
|
+
short body that links `CHANGELOG.md` at the tag itself (not at `main`) and
|
|
284
|
+
anchors straight to that version's dated heading, so the note a reader lands
|
|
285
|
+
on always matches the bytes RubyGems published.
|
|
120
286
|
|
|
121
|
-
|
|
287
|
+
### Stable branches
|
|
122
288
|
|
|
123
|
-
|
|
289
|
+
A stable branch is `N-M-stable`, cut from the release tag. Create one only when a released line needs a patch after a newer major has shipped on `main`; until then, `main` is the only branch. There is no stable branch today.
|
|
124
290
|
|
|
125
|
-
|
|
291
|
+
### What coding agents may do
|
|
126
292
|
|
|
127
|
-
|
|
293
|
+
Agents may run `release:prepare` and `release:reopen` when asked, report the commands those tasks print, and prepare the pull request. Agents must not edit `lib/woods/version.rb` or the `release-state` fences by hand, create or push tags, dispatch the release workflow, or run any form of `gem push`. See `.claude/skills/release-flow/SKILL.md`.
|