textus 0.47.0 → 0.47.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c87fe067b0988d187beac617c4540e1563d0f006a08d6090b2b483c699555d46
4
- data.tar.gz: 4f0503119ebf3eeff28d7a16aee8dc8c62673e6b41912e85bc3453e596075e65
3
+ metadata.gz: 027b10e6f16354d3fae852056f5ebe3f63f74fcc0096befb069d58074ccadb10
4
+ data.tar.gz: a8d46c59ed4d1cf53a0749577ac4284665b9ae65a137cffa968c7f53e9fd386f
5
5
  SHA512:
6
- metadata.gz: fde04b0339e798e545c98699462afaf2767a772f1e76811c4f8833b561b69d02b172e4879cf17ffaea1dd51f1930846007abf4523a801ccfb5525c53e1365b7f
7
- data.tar.gz: 10a4343781cb2251ba8f91121c0a89b1fe211702e7c5057693fce27357eee55c3abe6bfe7a88009ffc89f5fcc49ad6c44fcf258f532f5ac9d69d960857e833c6
6
+ metadata.gz: 9f9cd646c53fc78e467c0955ad847daeb890d46be8d5d8b2697fa7507eb728a8b541c4e4a9feaaba8be875a5a735b8a1fbfdbf7fbe8bf999e9f54ff39d9918e6
7
+ data.tar.gz: 7b8ae5bb3a6d8089a195ee5716d79b97397d4b5fa487750acb1b32bb9831d465d82789a8211a343dbc1d98102178adfe5396d3c24a91bf4a4ae2c96253e159d8
data/CHANGELOG.md CHANGED
@@ -9,6 +9,13 @@ The **gem version** (`0.x.y`) is distinct from the **protocol version**
9
9
  bump is a breaking change that requires a store migration; the gem version
10
10
  tracks both additive improvements and breaking protocol bumps independently.
11
11
 
12
+ ## 0.47.1 — 2026-06-04 — External entries are a non-build path
13
+
14
+ ### Fixed
15
+
16
+ - **`build` no longer materializes `external` derived entries.** External entries are generated by an out-of-band runner — textus only tracks their staleness. Previously they flowed through `Derived#publish_via` → `Pipeline.run` and hit a catch-all branch that emitted an empty payload and re-stamped the volatile `generated_at` (contrary to ADR 0070), which for an entry with publish targets would **clobber the runner's artifact with an empty render**. External is now skipped in `Derived#publish_via`, and `Pipeline.run` raises loudly if a non-projection source reaches it (only projection-derived entries are buildable).
17
+ - **`compute.command` is now parsed for `external` entries.** The parser read `compute["runner"]`, a key the manifest schema forbids (`COMPUTE_KEYS` allows `command`), so `External#command` was always `nil`. The data field is renamed `runner` → `command` and now reads `compute["command"]`.
18
+
12
19
  ## 0.47.0 — 2026-06-04 — Close the agent loop over MCP
13
20
 
14
21
  The edit→accept→rebuild loop now closes over a single MCP transport: `build` is surfaced to MCP, `init --with-agent` scaffolds a connectable agent setup, and connection-lifecycle hardening (whole-contract drift fingerprint + a connect-time event carrying the resolved role) underpins it.
@@ -1,5 +1,4 @@
1
1
  require "fileutils"
2
- require "time"
3
2
 
4
3
  module Textus
5
4
  module Builder
@@ -42,19 +41,25 @@ module Textus
42
41
  end
43
42
 
44
43
  def self.run(mentry:, deps:)
45
- # 1. Load sources + project + reduce
44
+ # 1. Load sources + project + reduce. Only projection-derived entries are
45
+ # buildable in-process; External entries are generated out-of-band and are
46
+ # filtered out upstream (Derived#publish_via), so reaching here with a
47
+ # non-projection source is a wiring bug — fail loudly rather than emit an
48
+ # empty payload (and never re-stamp the volatile generated_at, ADR 0070).
49
+ unless mentry.is_a?(Textus::Manifest::Entry::Derived) && mentry.projection?
50
+ raise UsageError.new(
51
+ "builder: '#{mentry.key}' is not a projection-derived entry; only projections are buildable",
52
+ )
53
+ end
54
+
46
55
  data =
47
- if mentry.is_a?(Textus::Manifest::Entry::Derived) && mentry.projection?
48
- Textus::Projection.new(
49
- reader: deps.reader,
50
- spec: mentry.source.to_h.transform_keys(&:to_s),
51
- lister: deps.lister,
52
- rpc: deps.rpc,
53
- transform_context: deps.transform_context,
54
- ).run
55
- else
56
- { "entries" => [], "count" => 0, "generated_at" => Time.now.utc.iso8601 }
57
- end
56
+ Textus::Projection.new(
57
+ reader: deps.reader,
58
+ spec: mentry.source.to_h.transform_keys(&:to_s),
59
+ lister: deps.lister,
60
+ rpc: deps.rpc,
61
+ transform_context: deps.transform_context,
62
+ ).run
58
63
  data = data.merge("boot" => deps.inject_boot.call) if mentry.inject_boot && deps.inject_boot
59
64
 
60
65
  # 2. Render
@@ -3,7 +3,7 @@ module Textus
3
3
  class Entry
4
4
  class Derived < Base
5
5
  Projection = ::Data.define(:select, :pluck, :sort_by, :transform)
6
- External = ::Data.define(:sources, :runner)
6
+ External = ::Data.define(:sources, :command)
7
7
 
8
8
  attr_reader :source, :template, :inject_boot, :events
9
9
 
@@ -21,6 +21,11 @@ module Textus
21
21
 
22
22
  def publish_via(pctx, prefix: nil) # rubocop:disable Lint/UnusedMethodArgument
23
23
  return nil unless in_generator_zone?(pctx.manifest.policy)
24
+ # External entries are produced by an out-of-band runner — textus has
25
+ # no in-process runner. The build path only tracks their staleness
26
+ # (Domain::Staleness::GeneratorCheck); materializing here would clobber
27
+ # the runner's artifact with an empty render. Skip the build entirely.
28
+ return nil if external?
24
29
 
25
30
  target_path = Textus::Write::Materializer.new(
26
31
  container: pctx.container, call: pctx.call,
@@ -47,7 +47,7 @@ module Textus
47
47
  transform: compute["transform"],
48
48
  )
49
49
  else
50
- Entry::Derived::External.new(sources: compute["sources"], runner: compute["runner"])
50
+ Entry::Derived::External.new(sources: compute["sources"], command: compute["command"])
51
51
  end
52
52
  end
53
53
 
@@ -1,4 +1,4 @@
1
1
  module Textus
2
- VERSION = "0.47.0"
2
+ VERSION = "0.47.1"
3
3
  PROTOCOL = "textus/3"
4
4
  end
@@ -2,8 +2,11 @@ require "fileutils"
2
2
 
3
3
  module Textus
4
4
  module Write
5
- # Materializes a single Derived manifest entry onto disk by running
6
- # the builder pipeline (template + projection + external runner).
5
+ # Materializes a single projection-derived manifest entry onto disk by
6
+ # running the builder pipeline (projection + template render). External
7
+ # entries are NOT materialized here — they are generated by an out-of-band
8
+ # runner and only staleness-tracked, so Derived#publish_via filters them out
9
+ # before reaching this point.
7
10
  # Extracted from Write::Build so that Publish can reuse
8
11
  # it without creating a Build dependency.
9
12
  class Materializer
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: textus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.47.0
4
+ version: 0.47.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Patrick