tldr-experts 0.10.0 → 0.11.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.
Files changed (47) hide show
  1. package/CHANGELOG.md +261 -0
  2. package/README.md +6 -2
  3. package/dist/hooks/answer-capture.js +297 -23
  4. package/dist/hooks/budget-gate.js +7 -7
  5. package/dist/hooks/{chunk-f6d6cp4h.js → chunk-5hyd1rk1.js} +9 -1
  6. package/dist/hooks/{chunk-3rwbyema.js → chunk-8d0t69pk.js} +1 -1
  7. package/dist/hooks/{chunk-gvs5fvve.js → chunk-b26rvgjd.js} +4 -1
  8. package/dist/hooks/{chunk-ecxt4p6n.js → chunk-gj1ckg0c.js} +21 -5
  9. package/dist/hooks/{chunk-14496ta8.js → chunk-h23db062.js} +32 -2
  10. package/dist/hooks/{chunk-dzm2bzqp.js → chunk-hx0jgrmh.js} +1 -1
  11. package/dist/hooks/{chunk-cmx01x0r.js → chunk-jmypgf6s.js} +56 -38
  12. package/dist/hooks/chunk-qn8qnrgw.js +103 -0
  13. package/dist/hooks/{chunk-dtpjhddq.js → chunk-rw3n3z6t.js} +23 -2
  14. package/dist/hooks/{chunk-br08fp2d.js → chunk-wbkwjpq2.js} +27 -19
  15. package/dist/hooks/{chunk-w3jssmwe.js → chunk-z6n9551r.js} +1 -1
  16. package/dist/hooks/{chunk-7ye9jde9.js → chunk-zs84arc1.js} +1 -1
  17. package/dist/hooks/claim-sources.js +5 -5
  18. package/dist/hooks/dod-gate.js +5 -5
  19. package/dist/hooks/no-reask.js +8 -8
  20. package/dist/hooks/session-start.js +37 -118
  21. package/dist/hooks/statusline.js +6 -6
  22. package/dist/tldrx.js +3111 -1269
  23. package/package.json +1 -1
  24. package/plugin/.claude-plugin/plugin.json +1 -1
  25. package/stages/build/stage.yml +14 -0
  26. package/stages/how/stage.yml +6 -0
  27. package/stages/plan/stage.yml +6 -0
  28. package/stages/watch/stage.yml +6 -0
  29. package/stages/what/stage.yml +6 -0
  30. package/templates/experts/stack/dotnet.md +4 -3
  31. package/templates/experts/stack/javascript.md +4 -3
  32. package/templates/experts/stack/python.md +4 -3
  33. package/templates/experts/stack/typescript.md +4 -3
  34. package/templates/workspace.yml +6 -0
  35. package/workflows/bugfix.yml +7 -0
  36. package/workflows/docs.yml +7 -0
  37. package/workflows/feature.yml +7 -0
  38. package/workflows/hotfix.yml +7 -0
  39. package/workflows/integration.yml +7 -0
  40. package/workflows/migration.yml +7 -0
  41. package/workflows/performance.yml +7 -0
  42. package/workflows/prototype.yml +7 -0
  43. package/workflows/refactor.yml +7 -0
  44. package/workflows/retro.yml +7 -0
  45. package/workflows/security-patch.yml +7 -0
  46. package/workflows/spike.yml +7 -0
  47. package/workflows/upgrade.yml +7 -0
package/CHANGELOG.md CHANGED
@@ -1,6 +1,267 @@
1
1
  # Changelog
2
2
 
3
3
 
4
+ ## 0.11.1 — 2026-09-08
5
+
6
+ ### Changed
7
+
8
+ - **The mandate now tells the driver what to READ, because the host's own context was the
9
+ bill.** Measured over one week of host sessions on three real workspaces: ~$8.5k at list,
10
+ 68 % of it Opus — and the work was not what cost it. Per-story time was a 0.6-1.35 h
11
+ median; the spend was 600-800-turn host sessions re-reading their whole context every
12
+ turn, one workspace alone at 2.5B cache-read tokens. `--tldr` already trims what the host
13
+ WRITES and what a sub-agent DELIVERS, and nothing anywhere told the host what to read
14
+ back. One bullet in the evidence discipline now does, in all four modes: a sub-agent's
15
+ outcome comes from its `result.json` and the ledger, never its transcript; each is briefed
16
+ to report its TURN in ten lines (a handoff is not a turn report — that one is a gate input
17
+ with its own contract, and trimming it costs the gate); and a cited file is re-opened to
18
+ VERIFY it at a gate, never re-read for a claim already made. It is paid for rather than
19
+ appended — the line budgets did not move (`MANDATE_MAX_LINES` 140, `MANDATE_TLDR_MAX_LINES`
20
+ 165, unattended still exactly at both) because the negative-case and contradiction bullets
21
+ each lost a line of wrapping to the same meaning and the unattended gate's interrupt
22
+ paragraph lost the clause that restated "## Do not stop".
23
+
24
+ ### Added
25
+
26
+ - **A run can now tell a person it needs them, without the framework naming a chat tool.**
27
+ `tldrx run auto` announced an open question or a gate by exiting `4` and printing a
28
+ decision card to stdout, and stdout is in a terminal nobody is watching — which is why
29
+ every run in the week of 2026-09-07 was driven in host mode instead, trading a metered
30
+ budget, an enforced model and parallel stories for a notification. `.tldrx/workspace.yml`
31
+ now takes one optional `notify:` block — a `command`, an optional `events:` list, an
32
+ optional `timeout_s` — and the loop hands that command one `version: 1` JSON object on
33
+ **stdin** at each moment a person is needed: the open question with its options, its
34
+ recommendation and the literal `tldrx answer <Qid> "…" --run <id>` line; a gate with the
35
+ literal approve line; a finished or failed run with its exit code and what that code's
36
+ family means; a budget warning with both numbers. The command is held to §2.1's rule
37
+ exactly — split to argv and run directly, never through a shell, a bare metacharacter
38
+ refused rather than shelled — and the payload never touches the command line, so a
39
+ question's own title cannot become shell syntax. Which service reaches the owner stays the
40
+ owner's decision: a built-in integration would be this framework deciding whose product it
41
+ depends on, which is the same reasoning the drive mandate has always given. `tldrx init`
42
+ writes the block commented out with a line saying what it is for, the way `test_fast` is
43
+ written — who gets woken up is not a thing to detect. Schema and payload: spec §2.18.
44
+ (#180)
45
+ - **A failing notifier is written down, never a refusal.** A command that will not split, a
46
+ binary that is not there, a non-zero exit, a hang — each becomes a `notify.failed` event
47
+ carrying the reason, and the run keeps the exit code it already had; a delivered one is
48
+ `notify.sent` with the kind, the exit code and the duration. Both are `cost_usd: 0` and
49
+ both join the closed `EVENT_TYPES` enum. "The owner was not told, and here is why" is a
50
+ fact about the run; "the chat tool was down, so the run failed" would make a side channel
51
+ load-bearing. (#180)
52
+ - **`tldrx run auto --notify-every <duration>`** sends the declared hook a periodic `status`
53
+ payload carrying what `tldrx run status` prints. It fires from a timer rather than between
54
+ iterations on purpose: the period when somebody most wants to know a run is alive is the
55
+ twenty minutes it is inside one stage. Off by default. Over a run that is PARKED it
56
+ reminds rather than reassures — the summary names the open questions, `command` is the
57
+ literal `tldrx answer` line and `detail.waiting_on` carries the ids. A heartbeat that went
58
+ on saying "nothing is waiting on you" while the run sat on somebody's answer was
59
+ reproduced in review with both flags on, and it is worse than silence, because a heartbeat
60
+ is believed. Parked-ness comes from the same predicate `--wait-answers` polls and `next`
61
+ parks on, never a second opinion. (#180)
62
+ - **`tldrx run auto --wait-answers <duration>`** polls the run's question files instead of
63
+ exiting `4` the moment a stage parks, and resumes if the question is answered — by a
64
+ person, or by whatever the notify hook reached — then exits `4` with the same lines it
65
+ always did, after one `question.timeout` notification, when the wait lapses. Nothing is
66
+ spent while it polls, and the loop never answers its own question: the answer is an
67
+ ordinary `tldrx answer`. Both flags take `30s`, `10m`, `2h` or a bare number of seconds
68
+ through one parser, and refuse anything else by name at exit `1`. Without either flag,
69
+ behaviour is unchanged for every existing user — a question or a gate still exits `4`, the
70
+ hook has simply already fired with the answer command in it. (#180)
71
+ - **The docs site now explains how to OPERATE a run unattended, not just what the flags
72
+ are.** The notify hook shipped with its schema in the spec and a paragraph in the driving
73
+ guide, and neither answers the question somebody actually has at 11pm: what do I write, and
74
+ what do I check when nothing arrives. A new guide page (EN + ES, in both sidebars) walks the
75
+ whole loop — host mode versus the engine with the honest trade-off, the `notify:` block and
76
+ its argv rule, the nine top-level payload keys with `question.raised` and `status` shown in
77
+ full and a per-kind table of the other six, a dependency-free ~30-line Node adapter you can
78
+ paste, `--notify-every` / `--wait-answers` with what exit `4` means when a wait lapses, a
79
+ first-run checklist that dry-runs the adapter on a hand-made payload before any run depends
80
+ on it, and troubleshooting for the four ways it silently does nothing. It names no
81
+ messaging service and it is not going to: the adapter is the reader's, and the page says
82
+ why in the same words the drive mandate does. (#180)
83
+
84
+ ## 0.11.0 — 2026-09-08
85
+
86
+ ### Fixed
87
+
88
+ - **An answered decision now says who decided it, and what it binds to.** `tldrx answer`
89
+ wrote a fact with no attribution and no repo scope, so a superseded owner call and an
90
+ unattended driver default read identically in `facts.yml` and in every prompt built from
91
+ it. `--decided-by <owner|driver>` (last one wins, like any ordinary flag) and repeatable
92
+ `--repo <name>` land on the fact `answer` writes — `--decided-by` outside the closed set,
93
+ or `--repo` naming no workspace repo, is a usage refusal (exit 1) with nothing written, and
94
+ `--repo` passed twice scopes once. With neither flag the fact says "not stated," never a
95
+ guessed owner. `Fact.decided_by` is additive on `facts.yml`; `Fact.repos` already existed
96
+ and is required, not additive. (#169)
97
+ - **Two signed facts that disagree produce a question, without an agent choosing to
98
+ notice.** The contradiction check now runs on every `answer`, scores the
99
+ new fact against the live ones in the same `area`, and — on a hit — RAISES an advisory
100
+ question (`asked_by: tldrx`, a new `advisory:` metadata key that opts a block out of
101
+ every reader that COUNTS open questions — the auto gate, `next`'s `awaiting_answer`
102
+ branch, `skip_if` and `tldrx status` — without hiding it from the readers that LIST
103
+ them, `tldrx questions` among them) rather than refusing the answer. The
104
+ new fact keeps `conflicts_with: [<id>]` naming the fact it contradicts (additive,
105
+ empty-omitted, unquoted) — which one is right is left to the question it raises, nothing in
106
+ the mechanism decides a "loser." "Not detected" never reads as "checked and agreed" — the
107
+ check is lexical, and honestly cannot catch what its own transcript produced here: three
108
+ differently-titled answers whose contents actually disagree. The new `fact.conflict_raised`
109
+ event (`{fact, conflicts_with, score, q, raised}`) joins the closed `EVENT_TYPES` enum.
110
+ (#169)
111
+ - **A defect in a file no story declared has a sanctioned remedy and a visible home.**
112
+ Reaching it used to mean a hand edit to a story's `touches:` while the boundary card
113
+ described exactly the verb that edit needed and the CLI forbade it. Separately, and by
114
+ owner decision REPORT ONLY — no new gate condition, no new refusal, no new exit code — a
115
+ Build finding whose file matches no story's declared surface now reaches the Build
116
+ handoff, the PR body and the boundary card (only when a boundary trigger already draws
117
+ one), named as unowned rather than silently absorbed by whichever story happened to run
118
+ last. (#171)
119
+
120
+ - **The developer bundle carries `result_schema` too, so both halves of one handshake make the
121
+ same promise.** Measured on disk in a real run: `.agent/<story>/pending.json` had no
122
+ `result_schema` while the reviewer bundle one directory down had one. The reviewer prompt says
123
+ in as many words to read the envelope shape out of the bundle and never from memory; the
124
+ developer had nothing to read it out of, so a host guessed the shape by copying a sibling
125
+ story's `result.json`, and a reviewer later "corrected" it from the other file. A developer
126
+ bundle — the Build story's, and every single-agent stage's — now carries the
127
+ `{outputs, questions_asked, notes}` envelope the spawned half is handed through
128
+ `claude --json-schema`, plus the `cost_usd` and `session_id` a host may declare and
129
+ `readResult` reads back. It is DERIVED from that schema rather than retyped, so a change to
130
+ the envelope cannot reach the spawn without reaching the bundle. The one thing the two halves
131
+ do not share is how strictly the schema is read, and that is now written down instead of
132
+ implied: a reviewer envelope is refused on its form, a developer envelope is coerced, and
133
+ `--commit --check` is what reports the difference.
134
+
135
+ ### Added
136
+
137
+ - **`tldrx story widen <id> <path>... --note "<why>"`** — the verb the boundary card had
138
+ been pointing at while the CLI forbade the hand edit it described. Records
139
+ `story.touches_widened` (`{story, paths, note, before, after}`, joining the closed event
140
+ enum) and rewrites `touches:` through the same validated write every other command uses.
141
+ Refused (exit 2, nothing written) for a `done` story — naming `reopen --for-fix` as the
142
+ remedy — a `..` anywhere in a path (a substring test, not a segment one), a path already declared, an unknown story, or a plan the
143
+ story doesn't have; an unresolved run is exit 3 (not found), and `--for-fix` is not a flag
144
+ of `widen` itself and passing it is a usage refusal (exit 1). (#171)
145
+ - **`tldrx budget grant <amount> --fact <id>`** — a ceiling that answers to a recorded
146
+ authorization instead of a bare number. Writes `authorized_usd` at run or phase scope, and
147
+ `authorized_by`/`authorized_at` always at the run level, citing the fact behind it (not
148
+ duplicated under a second key) — `--phase` scopes the amount, never the citation. Fires
149
+ `budget.granted` (`{amount_usd, fact, phase, note, ceiling_usd, previous_usd}`, joining the
150
+ closed event enum) — a second grant replaces the amount and the event records what it
151
+ replaced, `null` on the first grant; a non-positive amount is refused (exit 1, nothing
152
+ written), by the VALIDATOR as well as by the verb, so a hand-edited `authorized_usd: 0` —
153
+ which `grantFor` would otherwise read as a real $0 grant that blocks every later raise —
154
+ is a schema error rather than a record that quietly governs nothing. Absence is untouched:
155
+ no key still means no grant recorded, never `$0`. `on_grant_exceed` (default `warn`, distinct from and never confused with
156
+ `on_exceed`) says what a later `budget raise` past the grant does; `budget show` renders
157
+ the grant back and stays silent
158
+ when none is recorded. `--fact`/`--phase`/`--on-exceed` are refused (exit 1) on
159
+ `budget show` and `budget raise`, where recording a policy is not their job. All four keys
160
+ are additive on `budget.yml` — a file written before this change still loads and means no
161
+ grant. `DASHBOARD_MODEL_VERSION` is unchanged (3): `BudgetModel`/`BudgetPhaseModel` widen,
162
+ no existing field's meaning moved. (#170)
163
+ - **`tldrx cost --stories`** — what a story cost against the ceiling its spawn was given,
164
+ one row per story, ceilings keyed off each `agent.spawned`'s `max_budget_usd` and money
165
+ keyed off the envelope's own metered `cost_usd`. A story with an unmetered turn among its
166
+ metered ones is named a lower bound, never handed the unqualified "inside the ceiling"
167
+ verdict; a story with no spawned ceiling is reported as absent, not as a zero; a run with
168
+ no story spawns says so instead of printing an empty table. The same arithmetic now
169
+ appends an over-ceiling clause to the Build handoff's existing cost line when the stories
170
+ behind it ran over. (#170)
171
+ - **A run close, `run cancel`, `approve` and the Build handoff header all say how many of a
172
+ run's decisions name a decider.** One tally (`owner` / `driver` / not-stated), computed
173
+ once and read by all four surfaces; no sentence at all when the run recorded no facts,
174
+ never a confident zero. (#169)
175
+
176
+ - **`workspace.yml` gains an optional `test_fast:` command — the developer iterates on it, and
177
+ the suite runs once at the Definition of Done.** A story's ```dod block must be byte-equal to
178
+ a `workspace.yml` command, and the developer prompt hands the sub-agent that same list with
179
+ "these commands are the only ones you may run". Between them, the only test instrument the
180
+ framework offered was the whole suite. Measured this week on three real workspaces: in one of
181
+ them that suite is 11,929 tests over 855 files, and a developer iterating a story ran it six
182
+ to ten times, on top of the two or three the Definition of Done itself pays for (preflight
183
+ once per run, cached; then once per attempt). The waste was never the gate — it was the
184
+ iteration loop, for which there was no faster instrument. `test_fast` is that instrument, and
185
+ it is deliberately not evidence: it is declared, so the developer may run it, and a ```dod
186
+ line equal to it is REFUSED with a sentence that names the slot rather than the generic "not
187
+ one of workspace.yml's commands", which would be false about a command the file plainly
188
+ declares. `tldrx init` does not guess it — no manifest says which subset of a suite is the
189
+ fast one, and a synthesised answer is exactly the conventional wisdom `command_probes:` exists
190
+ to keep out of this file — so the emitted `workspace.yml` carries the slot commented out with
191
+ a line saying what it is for, and nothing probes a slot nobody declared. When the workspace
192
+ declares one, the developer prompt says both halves: iterate on the fast command, and run the
193
+ declared full command once before you stop, because the gate re-runs it after. When it does
194
+ not, the prompt is byte-identical to the one before this existed. Additive: `version:` stays
195
+ `1`, and every workspace written without the slot loads and behaves exactly as it did.
196
+ - **`tldrx next --commit --check` rehearses the commit and writes nothing, so a bad envelope
197
+ is caught while the turn is still open.** Measured on a real workspace this week: two reviews
198
+ were refused at `tldrx next --commit --review` because a `[src: …]` citation inside a `refuted`
199
+ finding was not the last thing on its line. Both refusals were correct; both arrived after the
200
+ turn had been paid for, and the host's answer was to ban `refuted` from the next thirty briefs
201
+ — a protocol feature switched off to dodge a late validator, which is the most expensive
202
+ possible outcome for a rule the framework got right. The reviewer cannot check itself: its
203
+ tools are `Read`, `Grep`, `Glob` and `Bash(git diff *)`, so there is no door to run a validator
204
+ through, and its prompt already states the end-of-line rule with a refused and an accepted
205
+ example generated from the reader's own patterns. What was missing was a way for the host to
206
+ ask "is this readable?" before saying the turn is done. `--check` validates the prepared
207
+ bundle's `result.json` through the SAME reader `--commit` uses — no second implementation of
208
+ the grammar, the dispositions or the verdict enum — prints every refusal verbatim with the
209
+ offending line, and exits `0` when `--commit` would read the envelope and `1` when it would
210
+ not. It takes no lock, moves no cursor, records no event and spends no attempt; the tests
211
+ compare `run.yml`, the story file and `events.jsonl` as bytes either side of the call. On a
212
+ developer bundle the reader is deliberately tolerant — a missing `outputs` is read as `[]`, a
213
+ non-string `notes` as `""` — so `--check` exits `0` and NAMES what is about to be coerced
214
+ rather than inventing a refusal the framework does not make. That naming goes down to the
215
+ ELEMENT, because the coercion that hides best is the one inside an array: `outputs` and
216
+ `questions_asked` are declared `items: {type: "string"}` and the reader silently FILTERS every
217
+ element that is not one, so `["good", 42, null, "also-good"]` is an array, passes any
218
+ whole-field type test, and still reaches the run as two entries. `--check` names each dropped
219
+ element by index and by the JSON of its value, through the same one-line predicate the reader
220
+ filters on — called, not restated, so the check cannot name a set the reader does not drop.
221
+ Nothing citable is lost in the bargain: a dropped element is by definition not a string, and a
222
+ `[src: …]` citation is a token inside one.
223
+
224
+ ### Changed
225
+
226
+ - **The shipped stage and workflow money literals are labelled `[assumption]`**, and
227
+ deliberately NOT recalibrated: `tldrx init` copies no `stages/` into `.tldrx/`, so moving
228
+ one moves the ceiling of every workspace that never wrote an override, and this repo holds
229
+ no corpus to derive a new number from. `triage.budget_basis` (closed set: `model-guess` /
230
+ `owner-grant` / `preset`; additive on `RunFile`'s `triage:`, absent means nothing) records
231
+ which of the three produced a triage's numbers — `tldrx seed apply` always writes
232
+ `model-guess` today. `tldrx cost --stories` is the command that would produce the corpus a
233
+ recalibration needs. (#170)
234
+
235
+ - **The Build stage ships `parallel: 2`, so a wave runs two stories at a time out of the box.**
236
+ `--parallel N` shipped in 0.3.1 and nothing used it: no shipped workflow and no shipped
237
+ stage file set it, so every workspace ran one story at a time by inheriting a code constant
238
+ nobody chose. Measured across three real workspaces over one week and 23 runs: runs of 34-43 h
239
+ wall clock whose per-story medians were 0.6-1.35 h — the wall clock was serialization, not work.
240
+ The stories of one wave are independent by construction (`waves.yml` puts every `depends_on` in
241
+ an EARLIER wave, and `validatePlan` refuses a plan that does not), so this is a schedule change
242
+ and not a correctness one; merges into the epic still happen serially, in the wave's listed
243
+ order, and so do the reviewers, whose merge base moves under them otherwise. Two rather than
244
+ more because one of those workspaces hit OOM kills at a wider fan-out — raise it per run with
245
+ `--parallel N`, or for good with `parallel: N` in your own `.tldrx/stages/build/stage.yml`.
246
+ `DEFAULT_PARALLEL` in code stays 1: the opinion belongs in the stage file an operator can read
247
+ and override, and the last resort stays the value that surprises nobody. The one thing
248
+ `parallel:` does not change is the `--prepare`/`--commit` handshake, which is per story and
249
+ stays sequential — that side cannot know how many sub-agents the host session will run. (#176)
250
+ - **The "can this test fail?" check now names its instrument: one test file, not the whole
251
+ declared suite.** The drive mandate asked for the one check a reviewer cannot do — break the
252
+ line a new test covers and watch it go red — and the four stack packs asked the same question
253
+ under `## Checks`, telling the reader to "re-run the test command declared in
254
+ `.tldrx/workspace.yml`". That command IS the full suite by construction: a story's Definition
255
+ of Done is byte-equal to a `workspace.yml` command. So the words nobody read as "full suite"
256
+ bought exactly that, once per mutation — measured over a week of unattended runs on three real
257
+ workspaces, five mutations in a story meant five extra full suites, six to ten suite runs per
258
+ story, against a suite of 11,929 tests over 855 files in one of those workspaces. The check
259
+ keeps earning its place (it caught a test that only passed because base64 hid a raw id); what
260
+ was expensive was the instrument. The mandate and all four packs now scope the mutation re-run
261
+ to the single test file that covers the broken line, and say where the declared command
262
+ belongs: once, at the Definition of Done. The empty-slot clause is untouched — a workspace
263
+ that declares no test command is still named rather than quietly passed.
264
+
4
265
  ## 0.10.0 — 2026-09-07
5
266
 
6
267
  ### Fixed
package/README.md CHANGED
@@ -163,8 +163,10 @@ its own refusal. See [10 Unattended mode](docs/guide/10-unattended-mode.md).
163
163
  | `security-patch` | auto | auto | — | human | human |
164
164
  | `migration` | auto | auto | auto | human | human |
165
165
 
166
- `--parallel <n>` on `next` / `run auto` builds that many of a wave's stories at once
167
- (merges still land in the wave's listed order; default 1 is unchanged).
166
+ `--parallel <n>` on `next` / `run auto` builds that many of a wave's stories at once. The
167
+ shipped Build stage declares `parallel: 2`, so a workspace that overrides nothing already runs
168
+ two lanes; the code fallback stays 1, for a stage file that says nothing. Merges still land in
169
+ the wave's listed order whatever the number is.
168
170
 
169
171
  A scope with `—` under `plan` does not run the Plan phase, and Build writes the one story that
170
172
  decision implies (`04-build/implicit-plan.yml`) from your What handoff rather than refusing;
@@ -314,6 +316,8 @@ back on the registry is 0.3.0.
314
316
 
315
317
  | Version | Date | Status | Contains |
316
318
  |---|---|---|---|
319
+ | 0.11.1 | 2026-09-08 | `beta` | operating a run when nobody is watching: the drive mandate now names the host's own context as the costliest instrument and tells the driver what to READ back — a sub-agent's outcome from its `result.json` and the ledger, never its transcript, each sub-agent briefed to report its turn in ten lines, and a cited file re-opened to VERIFY at a gate rather than re-read for a claim already made — paid for inside the unchanged line budgets rather than appended; `.tldrx/workspace.yml` takes one optional `notify:` block whose command is handed a `version: 1` JSON object on stdin at each moment a person is needed (an open question with its options, its recommendation and the literal `tldrx answer` line; a gate with its approve line; a finished or failed run with what its exit code's family means; a budget warning with both numbers), split to argv and never shelled, with a notifier that will not split, is not there, exits non-zero or hangs recorded as `notify.failed` instead of failing the run; `tldrx run auto --wait-answers <duration>` polls the question files and resumes when the answer lands instead of exiting 4 the moment a stage parks, and `--notify-every <duration>` sends a timer-driven heartbeat that reminds rather than reassures while a run is parked; and a new EN+ES guide page walks the whole unattended loop — host mode versus the engine, the payload keys, a dependency-free Node adapter, a first-run checklist and the four ways it silently does nothing — naming no messaging service, by the same reasoning the mandate has always given |
320
+ | 0.11.0 | 2026-09-08 | `beta` | governance that leaves a record: every answer says who decided it and what repo it binds, an advisory contradiction check raises a question that never stops a run and states its own limit, the close and the Build handoff count decided vs not-stated; `tldrx story widen` is the sanctioned way to grow a story's surface (a done story needs `reopen --for-fix` first) and a defect no story owns is named in the handoff, the PR body and the boundary card instead of absorbed; a budget grant is a recorded number in `budget.yml` that survives every writer, `budget raise` warns or refuses against it, presets are labelled as the assumptions they are, `triage.budget_basis` says where a figure came from and `tldrx cost --stories` measures each story against the ceiling its spawn was given, honest about lower bounds |
317
321
  | 0.10.0 | 2026-09-07 | `beta` | the mechanical blockers measured in real runs, fixed: a refused DoD command is recorded as refused (never a fabricated exit 126) in the event, the handoff, the review and retro logs, and the readers that used to recover it as green; the dirty-tree refusal prints the exact stash and pop commands and its true reason; the reviewer diffs the epic as it was before the merge (`epic_base` recorded on the story and the bundle) instead of an empty range; `tldrx init` probes each declared command once and records `command_probes` beside a `commands:` allowlist it never guesses; `tldrx ship` opens a PR whose body describes the change and its known defects, with the handoff folded underneath, and a state refusal that honours settled stories' declared touches; reviewer turns carry their token split and the spend basis reads it, so a whole provider no longer reads as absent |
318
322
  | 0.9.2 | 2026-09-07 | `beta` | the Build executor decomposed: 4,351 lines became an orchestrator plus eight modules under src/core/build/ (review ledger and phase cost, money caps, the DoD runner with its preflight cache, worktrees and epic-branch claims, the reviewer bundle and review round) — a pure refactor proven byte-for-byte by a golden guard over prompts, ordered events, run.yml rows and exit codes across three scenarios; no behaviour changed, every remaining hardening fix now lands in a file a reviewer can hold |
319
323
  | 0.9.1 | 2026-09-06 | `beta` | records and money that do not lie: a turn without a provider USD figure is unmetered, never a metered $0.00; a refusal no longer discards the turn's cost (banked first, deduped only against marked rows); an event over the 4096-byte cap spills its text beside the run and names it instead of losing every row of the invocation; preflight rows carry `command_hash` and their own `checked_at`, so a cached red is re-probed when the command changed, after 30 minutes, or under --prepare; the fix list writes back git's canonical 40-hex sha; `tldrx facts add` exists with owner/driver attribution rendered in prompts; run.yml rows carry the provider's token split only when reported |