woods 2.0.0.beta1 → 2.0.0.beta3
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 +400 -1
- data/CONTRIBUTING.md +224 -9
- data/README.md +7 -3
- data/SECURITY.md +9 -6
- data/docs/AGENT_GUIDE.md +83 -4
- data/docs/AGENT_SETUP.md +82 -1
- data/docs/BACKEND_MATRIX.md +20 -0
- data/docs/CLIENT_HOOKS.md +111 -0
- data/docs/CONFIGURATION_REFERENCE.md +233 -13
- data/docs/CONSOLE_MCP_SETUP.md +35 -5
- data/docs/DOCKER_SETUP.md +21 -2
- data/docs/EVALUATION.md +464 -1
- data/docs/EXTRACTOR_REFERENCE.md +36 -5
- data/docs/FAQ.md +11 -12
- data/docs/GETTING_STARTED.md +17 -5
- data/docs/INCREMENTAL_EXTRACTION.md +158 -2
- data/docs/INDEX_LAYOUT.md +382 -0
- data/docs/INTERNALS.md +15 -7
- data/docs/MCP_SERVERS.md +221 -5
- data/docs/MCP_TOOL_COOKBOOK.md +33 -18
- data/docs/NOTION_INTEGRATION.md +13 -0
- data/docs/OBSIDIAN_INTEGRATION.md +57 -9
- data/docs/PUBLISHED_INDEX.md +71 -0
- data/docs/README.md +7 -0
- data/docs/RETRIEVAL_GUIDE.md +253 -11
- data/docs/RUNTIME_TRACING.md +71 -0
- data/docs/SOURCE_FRESHNESS.md +143 -0
- data/docs/TROUBLESHOOTING.md +117 -5
- data/docs/UNBLOCKED_INTEGRATION.md +25 -0
- data/docs/UPGRADING_TO_2.md +44 -22
- data/docs/WATCH_DAEMON.md +259 -59
- data/exe/woods-agent-config +6 -0
- data/exe/woods-extract +5 -0
- data/exe/woods-hook-context +6 -0
- data/lib/generators/woods/templates/woods.rb.tt +1 -3
- data/lib/tasks/woods.rake +47 -397
- data/lib/woods/agent_configuration/applier.rb +133 -0
- data/lib/woods/agent_configuration/cli.rb +101 -0
- data/lib/woods/agent_configuration/cli_options.rb +29 -0
- data/lib/woods/agent_configuration/document.rb +105 -0
- data/lib/woods/agent_configuration/error.rb +7 -0
- data/lib/woods/agent_configuration/launcher.rb +75 -0
- data/lib/woods/agent_configuration/layout.rb +59 -0
- data/lib/woods/agent_configuration/managed_section.rb +62 -0
- data/lib/woods/agent_configuration/plan.rb +98 -0
- data/lib/woods/agent_configuration/plan_diff.rb +38 -0
- data/lib/woods/agent_configuration/planned_files.rb +61 -0
- data/lib/woods/agent_configuration/planner.rb +63 -0
- data/lib/woods/agent_configuration/planner_validation.rb +77 -0
- data/lib/woods/agent_configuration/preflight.rb +100 -0
- data/lib/woods/agent_configuration/recovery.rb +49 -0
- data/lib/woods/ast/node.rb +2 -0
- data/lib/woods/ast/parser.rb +38 -5
- data/lib/woods/atomic_file.rb +133 -3
- data/lib/woods/builder.rb +21 -5
- data/lib/woods/cache/cache_middleware.rb +28 -7
- data/lib/woods/cache/cache_store.rb +4 -5
- data/lib/woods/change_set.rb +5 -4
- data/lib/woods/console/credential_index.rb +20 -2
- data/lib/woods/console/credential_scanner.rb +14 -14
- data/lib/woods/console/credential_scanner_registry.rb +36 -0
- data/lib/woods/console/embedded_executor.rb +1 -1
- data/lib/woods/console/encrypted_credential_snapshot.rb +16 -0
- data/lib/woods/console/rack_middleware.rb +22 -13
- data/lib/woods/console/server.rb +18 -16
- data/lib/woods/dependency_graph.rb +65 -13
- data/lib/woods/embedding/corpus.rb +94 -0
- data/lib/woods/embedding/indexer.rb +90 -46
- data/lib/woods/embedding/openai.rb +17 -6
- data/lib/woods/evaluation/ablation_executor.rb +6 -1
- data/lib/woods/evaluation/ablation_timed_executor.rb +22 -4
- data/lib/woods/export/typed_reader.rb +56 -0
- data/lib/woods/extractor.rb +557 -228
- data/lib/woods/extractors/action_cable_extractor.rb +3 -1
- data/lib/woods/extractors/behavioral_profile.rb +9 -7
- data/lib/woods/extractors/caching_extractor.rb +3 -1
- data/lib/woods/extractors/concern_extractor.rb +64 -6
- data/lib/woods/extractors/configuration_extractor.rb +7 -3
- data/lib/woods/extractors/controller_extractor.rb +13 -4
- data/lib/woods/extractors/database_view_extractor.rb +3 -1
- data/lib/woods/extractors/decorator_extractor.rb +3 -1
- data/lib/woods/extractors/engine_extractor.rb +3 -1
- data/lib/woods/extractors/event_extractor.rb +4 -2
- data/lib/woods/extractors/factory_extractor.rb +3 -1
- data/lib/woods/extractors/graphql_extractor.rb +8 -2
- data/lib/woods/extractors/i18n_extractor.rb +3 -1
- data/lib/woods/extractors/job_extractor.rb +6 -19
- data/lib/woods/extractors/lib_extractor.rb +3 -1
- data/lib/woods/extractors/mailer_extractor.rb +20 -5
- data/lib/woods/extractors/manager_extractor.rb +3 -1
- data/lib/woods/extractors/method_parameters.rb +53 -0
- data/lib/woods/extractors/middleware_argument.rb +65 -0
- data/lib/woods/extractors/middleware_extractor.rb +9 -3
- data/lib/woods/extractors/migration_extractor.rb +3 -1
- data/lib/woods/extractors/model_extractor.rb +39 -33
- data/lib/woods/extractors/package_extractor.rb +24 -4
- data/lib/woods/extractors/phlex_extractor.rb +3 -1
- data/lib/woods/extractors/policy_extractor.rb +3 -1
- data/lib/woods/extractors/poro_extractor.rb +3 -1
- data/lib/woods/extractors/pundit_extractor.rb +3 -1
- data/lib/woods/extractors/rails_source_extractor.rb +4 -2
- data/lib/woods/extractors/rake_task_extractor.rb +4 -2
- data/lib/woods/extractors/route_extractor.rb +3 -1
- data/lib/woods/extractors/route_helper_resolver.rb +10 -33
- data/lib/woods/extractors/scheduled_job_extractor.rb +41 -15
- data/lib/woods/extractors/serializer_extractor.rb +4 -2
- data/lib/woods/extractors/service_extractor.rb +3 -1
- data/lib/woods/extractors/shared_dependency_scanner.rb +2 -2
- data/lib/woods/extractors/shared_utility_methods.rb +27 -15
- data/lib/woods/extractors/source_nesting.rb +1 -1
- data/lib/woods/extractors/state_machine_extractor.rb +3 -1
- data/lib/woods/extractors/test_mapping_extractor.rb +3 -1
- data/lib/woods/extractors/validator_extractor.rb +3 -1
- data/lib/woods/extractors/view_component_extractor.rb +3 -1
- data/lib/woods/extractors/view_template_extractor.rb +3 -1
- data/lib/woods/flow_assembler.rb +87 -8
- data/lib/woods/flow_precomputer.rb +44 -7
- data/lib/woods/gem_mapper.rb +2 -0
- data/lib/woods/git_history.rb +116 -0
- data/lib/woods/graph_analyzer.rb +195 -63
- data/lib/woods/hooks/context_cli.rb +54 -0
- data/lib/woods/hooks/context_event.rb +88 -0
- data/lib/woods/hooks/context_hint.rb +73 -0
- data/lib/woods/hooks/context_impact.rb +77 -0
- data/lib/woods/hooks/context_output.rb +47 -0
- data/lib/woods/hooks/context_state.rb +102 -0
- data/lib/woods/hooks/refresh.rb +79 -0
- data/lib/woods/hooks/rule_projection.rb +78 -0
- data/lib/woods/input_rules.rb +19 -0
- data/lib/woods/mcp/bearer_auth.rb +20 -12
- data/lib/woods/mcp/bootstrapper.rb +62 -0
- data/lib/woods/mcp/index_reader.rb +323 -160
- data/lib/woods/mcp/initialization_guidance.rb +27 -0
- data/lib/woods/mcp/origin_guard.rb +17 -9
- data/lib/woods/mcp/published_lexical_retriever.rb +115 -0
- data/lib/woods/mcp/renderers/markdown_renderer.rb +8 -1
- data/lib/woods/mcp/renderers/plain_renderer.rb +7 -1
- data/lib/woods/mcp/search_results.rb +74 -0
- data/lib/woods/mcp/server.rb +158 -37
- data/lib/woods/mcp/tool_contract.rb +2 -0
- data/lib/woods/mcp/tool_response_renderer.rb +25 -0
- data/lib/woods/mcp/traversal_evidence.rb +113 -0
- data/lib/woods/mcp/traversal_evidence_index.rb +100 -0
- data/lib/woods/mcp/traversal_evidence_page.rb +41 -0
- data/lib/woods/mcp/traversal_evidence_text.rb +52 -0
- data/lib/woods/notion/exporter.rb +56 -17
- data/lib/woods/obsidian/destination_plan.rb +98 -0
- data/lib/woods/obsidian/name_mapper.rb +19 -3
- data/lib/woods/obsidian/note_builder.rb +19 -10
- data/lib/woods/obsidian/vault_exporter.rb +88 -32
- data/lib/woods/operator/pipeline_guard.rb +18 -13
- data/lib/woods/path_dispatcher.rb +7 -1
- data/lib/woods/payload_store.rb +29 -15
- data/lib/woods/railtie.rb +3 -3
- data/lib/woods/railtie_support.rb +12 -12
- data/lib/woods/rake_helpers.rb +392 -0
- data/lib/woods/resilience/graph_invariant_validator/membership_checks.rb +71 -0
- data/lib/woods/resilience/graph_invariant_validator/node_checks.rb +61 -0
- data/lib/woods/resilience/graph_invariant_validator/reverse_relationship_checks.rb +46 -0
- data/lib/woods/resilience/graph_invariant_validator.rb +119 -0
- data/lib/woods/resilience/index_validator/graph_checks.rb +80 -0
- data/lib/woods/resilience/index_validator.rb +112 -23
- data/lib/woods/retrieval/context_assembler.rb +50 -15
- data/lib/woods/retrieval/lexical_assembler.rb +73 -0
- data/lib/woods/retrieval/lexical_index.rb +119 -0
- data/lib/woods/retrieval/ranker.rb +4 -2
- data/lib/woods/retrieval/scope.rb +108 -0
- data/lib/woods/retrieval/scoped_graph_store.rb +32 -0
- data/lib/woods/retrieval/scoped_vector_store.rb +55 -0
- data/lib/woods/retrieval/search_executor.rb +86 -27
- data/lib/woods/retrieval/source_evidence.rb +200 -0
- data/lib/woods/retriever.rb +98 -22
- data/lib/woods/ruby_analyzer/trace_enricher.rb +80 -38
- data/lib/woods/session_tracer/middleware.rb +10 -12
- data/lib/woods/session_tracer/redis_store.rb +22 -6
- data/lib/woods/session_tracer/session_flow_assembler.rb +23 -17
- data/lib/woods/session_tracer/solid_cache_coordination.rb +6 -4
- data/lib/woods/session_tracer/unit_resolver.rb +63 -0
- data/lib/woods/source_inputs/consumer_errors.rb +27 -0
- data/lib/woods/source_inputs/handoff.rb +102 -0
- data/lib/woods/source_inputs/launcher.rb +157 -0
- data/lib/woods/source_inputs/manifest.rb +124 -0
- data/lib/woods/source_inputs/private_key.rb +55 -0
- data/lib/woods/source_inputs/scanner.rb +171 -0
- data/lib/woods/source_inputs/scopes.rb +71 -0
- data/lib/woods/source_inputs/session.rb +214 -0
- data/lib/woods/source_inputs/status.rb +84 -0
- data/lib/woods/source_inputs/verifier.rb +107 -0
- data/lib/woods/storage/metadata_store.rb +25 -25
- data/lib/woods/storage/pgvector.rb +29 -8
- data/lib/woods/storage/qdrant.rb +17 -7
- data/lib/woods/storage/vector_store.rb +18 -6
- data/lib/woods/tasks.rb +3 -2
- data/lib/woods/temporal/json_snapshot_store.rb +29 -8
- data/lib/woods/unblocked/exporter.rb +59 -70
- data/lib/woods/version.rb +1 -1
- data/lib/woods/watch/boot_snapshot.rb +52 -0
- data/lib/woods/watch/daemon.rb +136 -28
- data/lib/woods/watch/listen_watcher.rb +4 -0
- data/lib/woods/watch/polling_watcher.rb +5 -1
- data/lib/woods/watch/status.rb +20 -15
- data/lib/woods/watch/tree_scan.rb +21 -13
- data/lib/woods/watch/watcher.rb +4 -1
- data/lib/woods.rb +135 -11
- data/plugin/.claude-plugin/plugin.json +1 -1
- data/plugin/hooks/adapters/normalize.jq +15 -0
- data/plugin/hooks/adapters/normalize.rb +63 -0
- data/plugin/hooks/hooks.json +20 -0
- data/plugin/hooks/woods-context.sh +50 -0
- data/plugin/hooks/woods-input-rules.sh +159 -0
- data/plugin/hooks/woods-opencode.mjs +65 -0
- data/plugin/hooks/woods-post-edit.sh +2 -225
- data/plugin/hooks/woods-refresh.sh +260 -0
- data/plugin/hooks/woods-session-start.sh +47 -55
- data/plugin/skills/woods-agent-enable/SKILL.md +13 -0
- data/plugin/skills/woods-diagnose/SKILL.md +288 -1
- data/plugin/skills/woods-investigate/SKILL.md +106 -0
- data/plugin/skills/woods-mcp-config/SKILL.md +89 -1
- data/plugin/skills/woods-setup/SKILL.md +107 -6
- metadata +84 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f1877858142850cdb2a9802c103198cf5be63439e610ebbc43cd10f97554f10d
|
|
4
|
+
data.tar.gz: 5bad5ce4acdb04312a53d31414ea0b93b3cb4d7c103209f3172bb84e509278c3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d878e5d2d4f51dcb4fcf4e39af29e78edf23eae756d0db4f2fe3b4c6e77454295d7a6f455d4d1f3aa397d70fb51253be040ca3ec29e17e32bd5d854dd4b434e4
|
|
7
|
+
data.tar.gz: 37a249bb634be55999c9d6ae1f058cd72a80be48496fc04b93d9d4213fa1355f1c7ff8d2d21abeeabaa8f88846846110a82547572ce74bce90dbb75d18133a0a
|
data/CHANGELOG.md
CHANGED
|
@@ -7,8 +7,398 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2.0.0.beta3] - 2026-09-18
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Optional `changelog/<type>_<slug>.md` entry files let parallel branches record changes without editing the same Unreleased block. `release:prepare` validates, folds, and removes consumed entries; release validation refuses leftover entries at the tagged SHA (B-179).
|
|
15
|
+
- Add optional `volatile_dependency_limit_per_target` to keep one hot dependency
|
|
16
|
+
from filling the volatility report (B-188). Apply the per-target edge cap before
|
|
17
|
+
the global top 20, preserve the default output, and expose the configured cap
|
|
18
|
+
and reported count alongside the full qualifying count when enabled.
|
|
19
|
+
|
|
20
|
+
- Gate retrieval quality in CI with a versioned Canopy runtime corpus, captured
|
|
21
|
+
real MiniLM vectors, per-strategy quality floors, latency observations, and
|
|
22
|
+
exact output-token counts. Preserve known failed queries in the evidence (#227).
|
|
23
|
+
- Bound `dependencies` and `dependents` traversal work independently of response
|
|
24
|
+
pagination, with configurable node/edge budgets and explicit partial-result
|
|
25
|
+
reasons. Filtered edges and reverse relationship checks consume the edge
|
|
26
|
+
budget; complete small results retain their existing shape (#311).
|
|
27
|
+
|
|
28
|
+
- Document the published filesystem layout for non-Ruby consumers, with pinned
|
|
29
|
+
Bash/jq and Python reads, retention-race handling, and structural snapshot
|
|
30
|
+
publication guidance (#306).
|
|
31
|
+
|
|
32
|
+
- `WOODS_WATCH_TRUST_FOREIGN_HOST=1` lets watch status, incremental/clean guards,
|
|
33
|
+
daemon startup checks, and MCP trust fresh foreign-container heartbeats without
|
|
34
|
+
checking an unrelated local pid. This is opt-in; foreign records expire after
|
|
35
|
+
15 minutes, and malformed or excessively future timestamps are rejected (#321).
|
|
36
|
+
|
|
37
|
+
- `WOODS_WATCH_POLL_INTERVAL` configures positive, finite seconds between watch
|
|
38
|
+
polling scans, including fallback from native watching (default 1.0; #322).
|
|
39
|
+
|
|
40
|
+
- Published manifests record `woods_version`, the last publisher's gem version,
|
|
41
|
+
for Rails extraction and static self-maps. MCP exposes it independently of the
|
|
42
|
+
reader version, and `woods:validate` gives nonfatal warnings for malformed
|
|
43
|
+
writer versions or different major versions. Older manifests remain valid
|
|
44
|
+
without this optional provenance field (#323).
|
|
45
|
+
- Supply concise, capability-aware Index MCP instructions through initialization and modern discovery, with status-first retrieval guidance, bounded traversal and source verification. Preserve the SDK's omission for protocol `2024-11-05`; tool registration and authorization remain unchanged. (#402)
|
|
46
|
+
- Added generation-bound source-input evidence with bounded `current` / `drifted` / `unknown` status, per-consumer incremental provenance, private keyed content identities, and a fresh-process `woods-extract` launcher. The opt-in session hook now checks source content through the shared no-environment status task. Old indexes and unproved boot/runtime consumption remain explicitly unknown.
|
|
47
|
+
Add separately opt-in, bounded Claude orientation and post-edit candidate context from a retained published generation, with explicit uncertainty, repeat suppression, independent refresh controls, and an installed `woods-hook-context` helper.
|
|
48
|
+
Explicit Claude and OpenCode edit adapters preserve every affected patch path,
|
|
49
|
+
including both rename sides, through the shared durable refresh queue. Native
|
|
50
|
+
OpenCode registration is optional and version-pinned; unsupported or escaping
|
|
51
|
+
events produce diagnostics without claiming refresh.
|
|
52
|
+
MCP `search` now reports whether its returned matches exhaust the requested domain, prove an additional match, or leave the remainder unknown after a scan budget or regex timeout. Bounded lookahead shares the existing scan budget, deep reads preserve typed identities, and detected artifact corruption remains an error. JSON and text formats distinguish returned counts from exact totals; agent guidance explains how to narrow partial searches. Mixed Rails/gem source directories remain searchable and loadable by lexical retrieval while rejecting unrelated type mismatches.
|
|
53
|
+
`woods:validate` now checks semantic graph invariants against typed unit indexes and artifacts within one pinned published generation. It detects broken reverse membership, invalid sources, duplicate typed variants, file/type index drift, and missing indexed nodes while accepting cycles, unresolved targets, legacy string edges, and the Woods static source map. Validation remains read-only, preserves existing report/exit behavior, and reports actionable identities without repairing the graph.
|
|
54
|
+
|
|
55
|
+
The validator, deep search, and lexical retrieval accept all four GraphQL unit types in the shared `graphql/` directory, preserving actual typed identities and existing directory-family search labels.
|
|
56
|
+
`dependencies` and `dependents` accept optional `explain: true` to retain typed source ownership, original edge direction and relationship attributes, and bounded shortest witnesses. Explanations distinguish direct records from transitive reachability, preserve unknown labels and ambiguous target candidates, and retain ancestor context across pages. Existing compact responses remain unchanged; explanation work shares traversal budgets.
|
|
57
|
+
Publish additive `reverse_via` target buckets with typed source identities, relationship labels and association attributes, preserving existing `reverse` arrays and legacy graph loading.
|
|
58
|
+
- Mark whole-file caching, configuration, test mapping, Rails source, and gem source graph nodes and typed variants with `kind: "file_profile"`, preserving file membership and identifiers while letting consumers distinguish profiles from constant-owned units (#417).
|
|
59
|
+
Add `woods-agent-config` for explicit Claude Code project/user setup, update, and removal. Preview saves one private edit plan; apply checks its original snapshots, preserves unrelated configuration, tracks owned entries and instruction sections, and supports recovery after interrupted writes. Host/Compose preflight checks the installed Index Server and published index.
|
|
60
|
+
- Add opt-in compact source evidence and declared API outlines to retrieval and lookup, with complete published spans, explicit omissions, honest generation/source provenance, and typed SHA-guarded full-source follow-up. Existing full-source behavior remains the default.
|
|
61
|
+
- Add explicit embedding-free lexical retrieval over published extraction units. Set `WOODS_RETRIEVAL_MODE=lexical` for Index MCP or `config.retrieval_mode = :lexical` for Ruby builders; field-aware ranked results preserve typed identity, generation consistency and budgeted matching evidence without provider or vector access. Semantic retrieval remains the default.
|
|
62
|
+
- Add explicit package and application-relative source-path scopes to ranked retrieval and discovery, with eligibility before candidate limits, typed scope metadata, and native scoped vector searches without re-embedding.
|
|
63
|
+
|
|
64
|
+
### Fixed
|
|
65
|
+
|
|
66
|
+
- Reflect model callbacks from Rails' per-event chains instead of nonexistent
|
|
67
|
+
per-kind readers; include `before_commit` and keep `callback_count` equal to
|
|
68
|
+
the emitted callback list. Preserve framework callbacks with stable Proc/lambda
|
|
69
|
+
source-site labels and address-free default callback-object descriptions in
|
|
70
|
+
metadata and chunks, including Rails 6's `raw_filter`, so separate-process
|
|
71
|
+
extractions of unchanged models remain equivalent. Preserve custom object labels.
|
|
72
|
+
|
|
73
|
+
- Explain the Zeitwerk 2.6.9 naming requirement in identifier-collision errors
|
|
74
|
+
and upgrade guidance before suggesting changes to valid namespace wrappers
|
|
75
|
+
on older-loader or classic-mode hosts (B-149).
|
|
76
|
+
|
|
77
|
+
- Stabilize controller inline callback and condition labels across processes and
|
|
78
|
+
checkout paths, including action chunks; retain `unless` conditions in the
|
|
79
|
+
generated filter-chain header (B-167).
|
|
80
|
+
|
|
81
|
+
- Publish metadata-only changes in local embedding snapshots without re-embedding
|
|
82
|
+
unchanged source; retain no-op dumps and source-hash checkpoints (B-119).
|
|
83
|
+
|
|
84
|
+
- Search Boolean metadata fields as `true`/`false` consistently in SQLite and
|
|
85
|
+
InMemory, preserving numeric `1`/`0` and null semantics (B-199, #356).
|
|
86
|
+
|
|
87
|
+
- Keep the default SQLite metadata database inside the effective `WOODS_OUTPUT`
|
|
88
|
+
directory for embedding tasks, isolating indexes while preserving explicit
|
|
89
|
+
database overrides (B-156). Existing databases are not moved; run `woods:embed`
|
|
90
|
+
for the selected index after upgrading.
|
|
91
|
+
|
|
92
|
+
- Treat non-object JSON snapshots and files removed or made unreadable during
|
|
93
|
+
a read as absent across lookup, listing, diffs, and unit history (B-158).
|
|
94
|
+
|
|
95
|
+
- Count corrupt and unreadable SHA-named JSON snapshots toward retention and
|
|
96
|
+
evict them before valid history, preserving the just-captured snapshot and
|
|
97
|
+
unrelated files (B-163).
|
|
98
|
+
|
|
99
|
+
- Count the final retrieval context after formatting and type-rank metadata,
|
|
100
|
+
keeping `tokens_used` and its trace consistent with the configured counter
|
|
101
|
+
or estimate (B-197, #354).
|
|
102
|
+
|
|
103
|
+
- Order tied hybrid retrieval candidates deterministically before graph seed
|
|
104
|
+
selection, truncation and reciprocal-rank fusion across supported Ruby versions
|
|
105
|
+
(B-192).
|
|
106
|
+
|
|
107
|
+
- Bound OpenAI embedding requests to 36 valid inputs, preserving chunk order and
|
|
108
|
+
rejecting partial or dimension-inconsistent batches (B-157). Chunk-heavy runs
|
|
109
|
+
use more HTTP requests to stay within the API's input and total-token limits.
|
|
110
|
+
|
|
111
|
+
- Match embedded NUL literally in SQLite metadata searches, including substrings after NUL; preserve ASCII case folding and literal wildcard characters (B-198, #355).
|
|
112
|
+
|
|
113
|
+
- Prevent single-component cache keys from colliding with multi-component or
|
|
114
|
+
empty keys by uniformly length-prefixing components (B-155). Custom callers
|
|
115
|
+
using persistent single-component keys should clear that cache domain on upgrade.
|
|
116
|
+
|
|
117
|
+
- Make middleware argument metadata, generated source and hashes stable across Rails processes by describing runtime identities structurally while preserving literal and nested configuration (#362).
|
|
118
|
+
|
|
119
|
+
- Omit per-unit git enrichment for shallow checkouts or unverifiable repository
|
|
120
|
+
depth, with one warning and full-history recovery guidance, instead of
|
|
121
|
+
reporting truncated commit counts as complete churn data (B-189).
|
|
122
|
+
|
|
123
|
+
- Validate direct/legacy Console scope arrays with the active SQL dialect and
|
|
124
|
+
MySQL session quote modes, refusing subqueries hidden by mismatched quote
|
|
125
|
+
stripping while retaining the supported tools' narrower scope grammar (B-154).
|
|
126
|
+
|
|
127
|
+
- Read and clear legacy Redis session indexes before any new record without
|
|
128
|
+
`WRONGTYPE`; atomic SET/ZSET access tolerates concurrent index migration
|
|
129
|
+
and keeps reader-only upgrades compatible with older SET writers (B-162).
|
|
130
|
+
|
|
131
|
+
- Allow full extraction when ActionMailer is absent and skip non-app mailers
|
|
132
|
+
instead of publishing empty units at fabricated paths; share that ownership
|
|
133
|
+
gate with incremental class discovery (B-153).
|
|
134
|
+
|
|
135
|
+
- Repair corrupt pipeline cooldown state on an explicit all-reset, including
|
|
136
|
+
`pipeline_repair` in custom operator-configured servers; ordinary reads still
|
|
137
|
+
deny operations and scoped resets preserve corrupt state (B-159).
|
|
138
|
+
|
|
139
|
+
- Normalize incremental change paths before deduplication and dispatch, including
|
|
140
|
+
trailing root slashes, repeated separators and dot segments (B-148).
|
|
141
|
+
|
|
142
|
+
- Load lazy Rails routes before caching navigation helpers, preserving view-to-controller dependencies during fresh-process incremental extraction (#360).
|
|
143
|
+
|
|
144
|
+
- Reflect model methods after schema loading so full and incremental runs agree
|
|
145
|
+
on Rails-generated constructors while preserving application overrides (B-202, #363).
|
|
146
|
+
|
|
147
|
+
- Parse job `perform_params` and shared `initialize_params` from Ruby parameter
|
|
148
|
+
syntax, avoiding phantom names from keyword/default expressions while preserving
|
|
149
|
+
the existing metadata fields and named rest/block arguments (B-151).
|
|
150
|
+
|
|
151
|
+
- Resolve ERB-backed Solid Queue recurring schedules using Rails configuration
|
|
152
|
+
loading, including relative requires, conditional entries, aliases and custom
|
|
153
|
+
environment sections (B-203, #364).
|
|
154
|
+
|
|
155
|
+
- Preserve navigation edges for real named routes such as `file_path`,
|
|
156
|
+
`image_url`, `download_path`, and `root_path`; unresolved asset/filesystem
|
|
157
|
+
helper names still produce no edge (B-152).
|
|
158
|
+
|
|
159
|
+
- Resolve and track app-owned nested model mixins through runtime source locations, refreshing includer source and callbacks on incremental edits (B-150, #361).
|
|
160
|
+
|
|
161
|
+
- Explain the full-extraction recovery for runtime job removals and bundle
|
|
162
|
+
upgrades; missing gem-path warnings now include the bundle-update remedy
|
|
163
|
+
without changing incremental discovery rules (B-165, B-166).
|
|
164
|
+
|
|
165
|
+
- Preserve all reverse dependencies on symbolic external targets such as `http_api` after incremental graph reloads and re-registration (B-193, #305).
|
|
166
|
+
|
|
167
|
+
- Preserve changes to nested `extracted_at` metadata when deciding whether to
|
|
168
|
+
rewrite a unit; only Woods' top-level extraction stamp is ignored (B-147).
|
|
169
|
+
- Read per-unit git enrichment in one streamed HEAD history walk instead of
|
|
170
|
+
repeated 500-path batches (B-195, #305). Merge commits compare with their first
|
|
171
|
+
parent while all HEAD ancestry is visited; counts can change from legacy
|
|
172
|
+
pathspec simplification. Optional enrichment now requires Git 2.31 or newer;
|
|
173
|
+
incomplete/failed history is omitted with a warning. Run full extraction
|
|
174
|
+
after upgrading to refresh retained metadata. Host speedup remains unmeasured.
|
|
175
|
+
|
|
176
|
+
- Apply the same app-owned path exclusions to full and incremental git enrichment;
|
|
177
|
+
external, vendored, and node_modules units no longer gain empty git metadata (B-194).
|
|
178
|
+
|
|
179
|
+
- Prune default excluded package directories before recursively discovering
|
|
180
|
+
`package.yml`, avoiding scans of indexes and snapshots under `tmp/` (B-196, #305).
|
|
181
|
+
|
|
182
|
+
- Preserve namespaced and CamelCase graph-retrieval subjects, keep snake_case
|
|
183
|
+
lookup working, and exclude tracing instructions from fallback metadata searches (B-190).
|
|
184
|
+
|
|
185
|
+
- Order equal PageRank scores by identifier before assigning retrieval importance
|
|
186
|
+
percentiles, making their ranking weights deterministic across Ruby versions
|
|
187
|
+
and graph insertion orders (B-191).
|
|
188
|
+
|
|
189
|
+
- Reduce payload-seed metadata lookups by classifying each entry once. Preserve
|
|
190
|
+
per-file hardlink/copy fallback, atomic publication and generation retention
|
|
191
|
+
while reducing full and incremental seed overhead (#305).
|
|
192
|
+
|
|
193
|
+
- Keep runtime trace evidence for same-name instance and singleton methods separate, including inherited singleton owners and caller kinds. Legacy untyped events enrich instance methods only; re-record old singleton traces.
|
|
194
|
+
|
|
195
|
+
- Ruby trace enrichment now records the nearest observed calling Ruby method
|
|
196
|
+
instead of the callee receiver. Recording keeps separate fiber stacks, handles
|
|
197
|
+
recursive and unwound calls, and leaves outside-recording callers unknown
|
|
198
|
+
without binding or backtrace inspection (#309).
|
|
199
|
+
|
|
200
|
+
- Scope per-file git metadata to HEAD history instead of every ref, excluding
|
|
201
|
+
unmerged branches and tool checkpoints from churn and authorship (#319). Run
|
|
202
|
+
a full `woods:extract` after upgrading to refresh previously published metadata.
|
|
203
|
+
|
|
204
|
+
- Full extraction no longer creates empty type directories at the index root
|
|
205
|
+
before publishing its generation payload. Existing root directories and legacy
|
|
206
|
+
flat-index files are preserved (#320).
|
|
207
|
+
|
|
208
|
+
- Watch startup reconciles environment-boot-covered restart inputs with one full
|
|
209
|
+
extraction instead of repeatedly exiting 75. Live changes and changes during
|
|
210
|
+
environment initialization still require restart; failed reconciliation and
|
|
211
|
+
deleted restart inputs survive retries and supervisor restarts. Built-in
|
|
212
|
+
watchers establish detection before startup extraction begins (#318).
|
|
213
|
+
|
|
214
|
+
- Add `console_mcp_http_enabled` (default `true`) so stdio-only Console setups
|
|
215
|
+
can explicitly disable HTTP and its boot-time token warnings. Production
|
|
216
|
+
still refuses to boot without a token when HTTP Console is enabled (#304).
|
|
217
|
+
|
|
218
|
+
- Solid Cache conditional writes on MySQL no longer claim ownership of a
|
|
219
|
+
pre-existing row when the adapter reports matched rows as affected rows.
|
|
220
|
+
Validate ownership using the per-attempt serialized payload, with live MySQL
|
|
221
|
+
contention/recovery coverage and documented crash/eviction limits (#228).
|
|
222
|
+
- Keep Notion model/column/migration data and Unblocked full/partial documents tied to their exact extracted type. Refuse incomplete export reads before mutation, and preserve remote documents when same-name, same-file types cannot be represented safely by Unblocked's existing URI scheme.
|
|
223
|
+
Preserve the selected extraction type when framework search and recent changes read colliding identifiers. Session controller lookup and root outgoing-edge selection now retain the controller type. Public untyped lookup, downstream references and the bare-name multi-step context pool retain their existing contracts.
|
|
224
|
+
Obsidian export preserves same-name units of different types, their separate outgoing links, and original public identifiers. Collision-bearing vaults publish a version-2 typed manifest; ordinary version-1 manifests and note paths remain unchanged. Ambiguous bare targets are omitted with a diagnostic, and incomplete typed reads cannot trigger stale-note deletion.
|
|
225
|
+
- Reject ambiguous cross-type dependencies in session context with an actionable `ambiguous_identity` MCP error instead of silently selecting a source or reusing another type's context key. Leave unresolved controllers in the timeline without a misleading source reference. Pin candidate discovery and all assembly reads to one generation; retain typed controller roots, metadata-only timelines, and successful response shapes. Refs #213; this does not migrate global identifiers.
|
|
226
|
+
- Refresh Console credential indexes from a fresh encrypted-file and key snapshot, retain the last valid index when refresh fails, and update all live embedded servers without retaining abandoned servers. Each response scan uses one complete credential index.
|
|
227
|
+
Keep credential scanner refresh snapshots limited to live weakly referenced
|
|
228
|
+
scanners on older Ruby versions, avoiding unsafe receiver access after garbage
|
|
229
|
+
collection while preserving updates to every live Console server.
|
|
230
|
+
- Refuse incomplete native embedding input before changing stores or checkpoints, retaining legacy flat-index support while rejecting malformed JSON. A source-empty unit now retires superseded vectors and checkpoints its no-content state without calling the embedding provider (#442, #444).
|
|
231
|
+
- Terminate the evaluation command's owned process group on timeout, including ordinary descendants whose parent has already exited.
|
|
232
|
+
- Let only the hook that removes a recorded dead-owner marker replace its mkdir lock, so concurrent recovery does not leave all edits queued behind an abandoned empty directory.
|
|
233
|
+
- Refuse Obsidian exports that would overwrite unmanaged notes, indexes, settings, or sidecars. Preflight all destinations, record generated asset digests separately from the public manifest, and suppress sweeps on conflicts or write failures. Legacy assets are adopted only when byte-identical; changed legacy sidecars require inspection and backup or a fresh export directory.
|
|
234
|
+
- Coordinate `Woods.extract!` and `Woods.extract_changed!` with task/watch writers and raise on lock timeout or failed generation publication, so background jobs can retry unsuccessful extraction.
|
|
235
|
+
- Accept Rails 6.0 positional middleware options on Ruby 3 while preserving explicit keyword precedence, required bearer tokens, and unknown-option refusal. Add an installed-gem CI contract for all advertised direct runtime dependency floors, with a constrained Rails 6.0.0 fixture and recorded transitive resolution.
|
|
236
|
+
- Honor configured context-token defaults in Builder-created semantic/lexical retrieval, caches, and MCP while preserving explicit budgets and the legacy custom-collaborator fallback. Deprecate the inert similarity_threshold option with a warning instead of changing ranking behavior (#446).
|
|
237
|
+
- Preserve the dispatched controller's runtime class name in session traces, with a Rails-inflector fallback, so acronym namespaces retain source context in `session_trace`.
|
|
238
|
+
- Preserve each logical directory alias in polling and startup catch-up so an earlier irrelevant alias cannot hide an extraction input such as `app/models`. Detect cycles per traversal branch while retaining ignored-subtree pruning.
|
|
239
|
+
|
|
240
|
+
### Changed
|
|
241
|
+
|
|
242
|
+
- Clarify the existing search-regex timeout exclusion: Ruby 3.0/3.1 remain
|
|
243
|
+
supported without a per-match time bound. Run the Index MCP process on Ruby
|
|
244
|
+
3.2+ for the one-second per-match limit; no runtime mitigation was added
|
|
245
|
+
for older interpreters (B-161).
|
|
246
|
+
|
|
247
|
+
- Reduce payload-clone allocation and traversal overhead while preserving
|
|
248
|
+
hardlinks, copy fallback and immutable generation ownership (#305).
|
|
249
|
+
- Make extraction profiling additive: report git enrichment, reconciliation,
|
|
250
|
+
finalization, pointer publication and retention separately, with a distinct
|
|
251
|
+
whole-run wall-time line (#305).
|
|
252
|
+
- Expand opt-in refresh hooks to the shared extraction input rules, including
|
|
253
|
+
services, controllers, jobs, views, locales, and supported tests/lib paths.
|
|
254
|
+
Restart inputs request fresh full extraction. Preserve queued edits across
|
|
255
|
+
failures and daemon deferral, bound the worker lifetime, and carry JSON batches
|
|
256
|
+
through Docker command prefixes without host-bundle or environment-forwarding
|
|
257
|
+
assumptions. Existing manual incremental and watch behavior is unchanged.
|
|
258
|
+
Add a trusted, disabled-by-default release profile for the supported 1.6.2 security maintenance line. Publication requires a separately reviewed exact candidate SHA pin on main, all fixed maintenance CI rows, and the existing immutable artifact and protected publication safeguards. The v2 release path retains its existing requirements.
|
|
259
|
+
|
|
260
|
+
### Documentation
|
|
261
|
+
|
|
262
|
+
- Clarify that source literals and optional session traces can contain sensitive information, and correct the session FileStore configuration example.
|
|
263
|
+
- Qualify the `~> 2.0` installation examples for stable releases and direct prerelease adopters to the exact published version in the README release table. Keep agent setup and plugin guidance aligned with installed-version capabilities; clarify that the refresh-hook deadline starts after complete event input is collected and queued.
|
|
264
|
+
|
|
265
|
+
### Testing
|
|
266
|
+
|
|
267
|
+
- Raise the default-suite CI line-coverage floor from 85% to 90%, calibrated against current local and CI measurements. Branch coverage remains measured without a gate; per-file floors and combined opt-in coverage remain separate work.
|
|
268
|
+
|
|
269
|
+
## [2.0.0.beta2] - 2026-09-10
|
|
270
|
+
|
|
271
|
+
### Added
|
|
272
|
+
|
|
273
|
+
- **`release:prepare` runs a live preflight before printing the tag and dispatch
|
|
274
|
+
commands.** The new `release:preflight` task (also runnable standalone) checks, via
|
|
275
|
+
`gh api`, that the live `release` environment still requires review and disallows admin
|
|
276
|
+
bypass; that `REQUIRED_CI_JOBS` in `script/validate-release-run` still matches
|
|
277
|
+
`ci.yml`'s job names; and that both `release.yml` download-artifact steps set
|
|
278
|
+
`merge-multiple: true`. Every check is advisory: a missing or failing `gh` skips with a
|
|
279
|
+
note rather than blocking prepare. CONTRIBUTING.md and the release-flow skill also gained
|
|
280
|
+
a "when a dispatch fails" guide (which failures a main merge alone fixes versus which need
|
|
281
|
+
the tag moved, and only before publication) and the documented final step for creating the
|
|
282
|
+
GitHub Release entry by hand, which the workflow deliberately never automates.
|
|
283
|
+
- **A release_v2 spec greps `spec/` for hard-coded current-version literals** (`'= 2.0.0'`,
|
|
284
|
+
`"2.0.0\n"`, `gem_version: '2.0.0'`-shaped strings), built from `Woods::VERSION`'s base, so
|
|
285
|
+
the next version bump cannot leave one behind the way the beta1 cut did.
|
|
286
|
+
- **`WOODS_PROFILE=1` logs a timing line per extraction phase.** The per-extractor
|
|
287
|
+
lines already reported extraction itself; everything after it (payload seed, previous
|
|
288
|
+
graph load, eager load, blast radius, re-extraction, type index, graph analysis, flows,
|
|
289
|
+
manifest and summary, publish) was unattributed, so a slow run could only be split by
|
|
290
|
+
guessing. One `[Woods] [profile] <phase> in N.NNs` line per phase, on the monotonic
|
|
291
|
+
clock. Off by default and free when off.
|
|
292
|
+
- **`durable_payload_writes` restores the per-file `fsync` on payload files.** Boolean,
|
|
293
|
+
default `false`. Off is not the weaker setting: readers resolve only through
|
|
294
|
+
`generation.json`, and every publish now flushes the whole payload before writing that
|
|
295
|
+
pointer, so the contract holds either way. Turning the key on buys exactly one thing, an
|
|
296
|
+
individual payload file being durable before the pointer exists, and pays two forced
|
|
297
|
+
flushes per file (about 8.9ms each on btrfs) for it. It cannot disable the publish
|
|
298
|
+
flush, which has no opt-out.
|
|
299
|
+
|
|
300
|
+
- **`incremental_blast_radius_depth` bounds how far an incremental run re-extracts.**
|
|
301
|
+
`extract_changed` walked the unbounded transitive dependent closure of every changed
|
|
302
|
+
file, so one edit to a widely referenced unit re-extracted most of the app. The new key
|
|
303
|
+
caps the walk at N reverse hops (`nil`, the default, keeps the unbounded closure). A
|
|
304
|
+
unit outside the cap keeps its content and still gets its `dependents` list refreshed by
|
|
305
|
+
the run's second pass, which the equivalence harness now covers under a cap of 1. The
|
|
306
|
+
default stays unbounded on purpose: an STI grandchild inherits its grandparent's
|
|
307
|
+
associations, validations and callback chain while sitting two hops away in the graph,
|
|
308
|
+
and nested `has_many :through` resolves the same way, so a host opts in for a tree it
|
|
309
|
+
knows has neither. On a 200-service chain in the dummy app, one leaf edit re-extracts
|
|
310
|
+
200 units unbounded and 2 under a depth of 1.
|
|
311
|
+
|
|
312
|
+
### Changed
|
|
313
|
+
|
|
314
|
+
- **Payload durability moved from every file to the generation pointer.** `AtomicFile.write`
|
|
315
|
+
fsynced the temp file and the containing directory for every file it wrote, so a full
|
|
316
|
+
extraction of a large application paid two forced flushes 8323 times: 71.3s of the write
|
|
317
|
+
phase for 8000 files on btrfs, against 1.0s for one filesystem flush. Payload writes (unit
|
|
318
|
+
files, type indexes, the dependency graph, the graph analysis, the manifest, the summary,
|
|
319
|
+
the flow documents) now skip both, and `publish_generation` calls the new
|
|
320
|
+
`AtomicFile.sync_directory_tree` on the payload directory immediately before writing
|
|
321
|
+
`generation.json`.
|
|
322
|
+
|
|
323
|
+
The guarantee that replaces the old one: **when `generation.json` is durable, every file
|
|
324
|
+
in the payload it names is durable.** What is given up is an individual payload file being
|
|
325
|
+
durable before the pointer exists, and nothing reads a payload file in that window, since
|
|
326
|
+
every reader resolves through the pointer and a crash there leaves an unreferenced partial
|
|
327
|
+
payload the next run prunes. `generation.json` itself, the watch daemon's status file, the
|
|
328
|
+
update check cache, the Obsidian and Unblocked exports, Notion sync state, temporal
|
|
329
|
+
snapshots, embedding checkpoints and MCP task records all keep the per-file fsync: their
|
|
330
|
+
readers do not go through the pointer. The gem mapper's self-map publishes through the
|
|
331
|
+
same pointer but keeps its per-file fsync for now; it is a small payload and adopts the
|
|
332
|
+
single flush in a follow-up.
|
|
333
|
+
|
|
334
|
+
`sync_directory_tree` tries `syncfs(2)` through Fiddle, then `sync -f <dir>`, then a bare
|
|
335
|
+
`sync`, then an `fsync` on every file in the tree, and returns which one ran. The last
|
|
336
|
+
resort is what keeps this honest: the chain never silently does nothing, it only gets
|
|
337
|
+
slower. Fiddle is required inside a rescue and stays out of the gemspec, since it is a
|
|
338
|
+
bundled gem from Ruby 3.5. `bench/atomic_write_bench.rb` measures all four modes.
|
|
339
|
+
|
|
340
|
+
- **Seeding a payload creates each directory once rather than once per file.**
|
|
341
|
+
`PayloadStore#clone` ran `FileUtils.mkdir_p` before every file it replicated.
|
|
342
|
+
`Pathname#find` visits a directory before its children, so the directory branch had
|
|
343
|
+
already created every parent a file could need. 8001 files across four type directories
|
|
344
|
+
on btrfs: 0.906s before, 0.847s after.
|
|
345
|
+
|
|
346
|
+
- **Cycle detection is capped, and says so.** `GraphAnalyzer#analyze` runs on every
|
|
347
|
+
extraction regardless of the change set, and enumerating every cycle was the largest
|
|
348
|
+
part of it: one cycle per DFS back-edge, uncapped in count and in length, each
|
|
349
|
+
canonicalized by joining a path that on a deep DFS is thousands of nodes long. Two new
|
|
350
|
+
config keys bound it, `graph_cycle_limit` (default 500) and `graph_cycle_max_length`
|
|
351
|
+
(default 50, in distinct nodes); either firing sets the new
|
|
352
|
+
`stats.cycle_limit_reached` in `graph_analysis.json`. Set either to `nil` to remove
|
|
353
|
+
its cap and restore exhaustive enumeration. Signatures are now keyed by a digest of
|
|
354
|
+
the rotated cycle rather than the joined path. On a synthetic 8201-node graph, cycle
|
|
355
|
+
detection went from 8.6s to 0.4s.
|
|
356
|
+
- **Bridge detection reuses its work.** `bfs_shortest_path` carries parent pointers
|
|
357
|
+
instead of enqueueing a copy of the path so far for every node it reaches, and forward
|
|
358
|
+
adjacency resolves through a per-analyzer memo instead of being re-derived on each of
|
|
359
|
+
the 200 sampled traversals. Output is unchanged. On the same graph, bridges went from
|
|
360
|
+
2.2s to 0.6s and the whole report from 3.1s to 1.0s.
|
|
361
|
+
- **Flow assembly caches loaded units and parsed sources.** One `FlowAssembler` serves a
|
|
362
|
+
whole precompute run, but nothing was cached across it: a unit's JSON was re-globbed
|
|
363
|
+
and re-parsed on every expansion, and its source re-parsed once per action of every
|
|
364
|
+
controller that reached it. Three per-instance LRU memos (unit data, whole-source AST,
|
|
365
|
+
and the method index derived from it) bound at 1000 entries each. On 435 controllers x
|
|
366
|
+
7 actions over 3000 services, precompute went from 20.5s to 3.8s.
|
|
367
|
+
- **The manifest and `SUMMARY.md` read each type index once.** Both derive their totals
|
|
368
|
+
from the per-type `_index.json` files and run back to back at the end of every
|
|
369
|
+
incremental run, so every index was globbed, read and parsed twice. An unreadable index
|
|
370
|
+
still drops that type from both, now with one warning instead of two.
|
|
371
|
+
- **The incremental flow refresh is scoped to the flow assembly radius.** Flows were
|
|
372
|
+
reassembled for every controller in the run's touched set, and the touched set is the
|
|
373
|
+
graph's whole reverse closure, so one leaf edit re-ran flow assembly for nearly every
|
|
374
|
+
controller in the app. A flow document reaches `FlowPrecomputer::DEFAULT_MAX_DEPTH`
|
|
375
|
+
units, so the run now walks the pre-change graph to that same depth and reassembles
|
|
376
|
+
only the controllers inside it. Controllers outside it carry their
|
|
377
|
+
`metadata[:flow_paths]` annotation forward out of the previous flow index rather than
|
|
378
|
+
losing it. A targeted `refresh`, a routes re-run, and a controller whose action set no
|
|
379
|
+
longer matches the index all still reassemble in full. On 50 controllers over a
|
|
380
|
+
50-service chain in the dummy app, one edit at the far end went from 50 controllers
|
|
381
|
+
reassembled to 3 plus 47 carried.
|
|
382
|
+
- **`graph_sha` is digested from the bytes written.** `graph_analysis.json`'s digest of
|
|
383
|
+
`dependency_graph.json` came from reading the file back off disk, one whole-file read
|
|
384
|
+
per run of an artifact that on a large app is tens of megabytes, to digest bytes the
|
|
385
|
+
run had just serialized. The value is unchanged.
|
|
386
|
+
|
|
10
387
|
### Fixed
|
|
11
388
|
|
|
389
|
+
- `TraceEnricher.record` rejects calls without a block before creating a
|
|
390
|
+
TracePoint, preventing an enabled hook from leaking into subsequent execution (#308).
|
|
391
|
+
|
|
392
|
+
- **The Changed list only names the surface inventory when regenerating it actually moved
|
|
393
|
+
it.** `release:prepare` used to list `.Codex/release-v2/surface-inventory.json`
|
|
394
|
+
unconditionally, even on the ordinary run where nothing in the public surface changed.
|
|
395
|
+
- **The release banner no longer links an upgrade guide that does not exist yet.** A major
|
|
396
|
+
version bump past `docs/UPGRADING_TO_2.md`'s own major derived a
|
|
397
|
+
`docs/UPGRADING_TO_<major>.md` link without checking the file exists.
|
|
398
|
+
- **Changelog entries merged from a duplicate heading no longer carry a stray blank line.**
|
|
399
|
+
Two occurrences of the same `###` heading in one `## [Unreleased]` cycle folded into a
|
|
400
|
+
release section with a blank line between their bullets, splitting one list into two; they
|
|
401
|
+
now join tight.
|
|
12
402
|
- **Release validation names the live-backends CI job as it is called.** The release
|
|
13
403
|
validator required a CI job named `Live backends (pgvector + Qdrant + Solid Cache)`,
|
|
14
404
|
but the job gained `+ Redis` in its name, so every release dispatch failed at
|
|
@@ -23,6 +413,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
23
413
|
snapshot fixture, so the first prerelease failed them (Bundler never resolves a prerelease
|
|
24
414
|
from an unpinned requirement). They now use `Woods::VERSION`. The candidate host also
|
|
25
415
|
installs `webrick` so `woods-mcp-http` finds a Rack handler on Rubies that no longer ship one.
|
|
416
|
+
- **Inspector contract specs track the pinned `@modelcontextprotocol/inspector` version instead
|
|
417
|
+
of a literal.** Bumping the dev dependency to 2.6.0 fixed the SDK bug where Inspector sent a
|
|
418
|
+
legacy `logging/setLevel` call after negotiating the modern 2026-07-28 protocol, so the two
|
|
419
|
+
`pending` stdio/HTTP examples in `mcp_inspector_contract_spec.rb` asserted a stderr message
|
|
420
|
+
that no longer occurs. Those examples now assert a clean modern handshake, and every version
|
|
421
|
+
literal in that file reads from `package.json` instead. `sdk_dependency_spec.rb`'s deliberate
|
|
422
|
+
version-and-integrity trip wire is bumped to match the new pin.
|
|
26
423
|
|
|
27
424
|
## [2.0.0.beta1] - 2026-09-09
|
|
28
425
|
|
|
@@ -300,7 +697,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
300
697
|
a previous version migrates automatically on the first record through a
|
|
301
698
|
single atomic server-side script, so concurrent writers racing the legacy
|
|
302
699
|
index cannot erase each other's members or fail mid-migration; eviction
|
|
303
|
-
order
|
|
700
|
+
order follows oldest last request for newly scored members. Migrated members
|
|
701
|
+
receive score zero and evict lexicographically until recorded again (B-160).
|
|
702
|
+
Adds a live-Redis contract spec
|
|
304
703
|
(`spec/session_tracer/redis_store_live_spec.rb`, `WOODS_RUN_LIVE_BACKENDS=1`).
|
|
305
704
|
|
|
306
705
|
### Documentation
|