tldr-experts 0.18.3 → 0.20.0

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,117 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.20.0 — 2026-09-13
4
+
5
+ ### Added
6
+
7
+ - **`tldrx seed check <file|dir>` — a read-only seed validator, and `/tldrx-plan`, a second
8
+ managed skill that plans seeds a run can finish (#291).** Measured this week across four
9
+ unattended runs on two workspaces: the difference between a run that finishes alone and one
10
+ that needs four rescues is decided BEFORE `run new`, in the seed — and nothing in the
11
+ framework helped a person write one. `install --claude` installed exactly one skill, the
12
+ facilitator; the only authoring guidance was the hand-written grammar list in the seeds
13
+ guide, which said nothing about stories, `touches`, `dod` lines, dependencies, size or
14
+ boundaries; the seeds that ran cleanly were written by a subagent that had to build its own
15
+ validator to check them. `seed check` is that validator, in the CLI: the seed goes through the
16
+ SAME importer chain `run new --seed` runs (`collectSeeds` → `seedClaims` →
17
+ `renderSeedHandoff` → `validateHandoff`, into a temp dir that stands in for the run dir), and
18
+ then through the authoring rules each traceable to a run that died without it — bullets
19
+ under 200 characters, `[src:]` last on its line and resolving to a real line, `dod` lines
20
+ byte-equal to a `commands:` value with no shell separator (`unquotedShellSeparator`, the
21
+ gate's own reader), a `Recommended:` on every open question (#251), `touches:` +
22
+ `depends_on:` + a ```dod fence on every story, and no two stories sharing a touched file in
23
+ one wave (#286: one conflicted file became four). One `file:line rule — text` line per
24
+ finding, exit `1`; an `advisory:` line for more than 4 stories or 2 waves — the framework's
25
+ CURRENT limit, named as a patch for #286/#244/#280 so the number is never read as a design
26
+ preference — never moves the exit code. `--budget <usd>` prints the stage split `run new`
27
+ would write and the per-story developer and reviewer caps, off `planBudget` and `caps.ts`
28
+ as they are (#244/#289: a `--budget 60` feature run gives Build $10.80 per attempt, and
29
+ nobody was told). Nothing here is a second reading of a rule: every check calls the function
30
+ that enforces it at run time. The planning skill, `plugin/skills/tldrx-plan/SKILL.md`, is
31
+ installed by `tldrx install --claude` beside the facilitator under the same
32
+ `<!-- tldrx-managed -->` marker, the same foreign-file refusal (a `SKILL.md` without the
33
+ marker at EITHER path refuses the whole install, nothing written) and the same uninstall;
34
+ `--dry-run` lists it as its own row. It reads `workspace.yml` and the repo tree before
35
+ writing, splits work into runs sized to what the framework carries today, chains stories
36
+ that share a counted or snapshot file, names only declared tools (patch for #290 — the
37
+ planner checks by hand what Plan cannot yet detect; the cure names tool + subcommand, and a
38
+ `git` line is never a `commands:` slot), gives every question a `Recommended:`, derives the
39
+ budget with `seed check --budget`, and ends with the exact
40
+ `run new … --gates none --questions none --ship merge` line. Every rule in the skill and on
41
+ the guide page is marked either **craft** (holds for any version) or **patch for #N**
42
+ (delete when the issue closes) — and the skill CITES the guide for the grammar instead of
43
+ restating it, which `test/plan-skill.test.ts` pins the way `test/maintain-skill.test.ts`
44
+ pins the maintain skill. The seed guide's "Writing a seed by hand" gained the story rules
45
+ with the same markers; the unattended recipe, both documentation sites (EN and ES) and the
46
+ README quick start name the validator and the skill.
47
+
48
+ ### Fixed
49
+
50
+ - **A permission refusal the workspace's `commands:` could have granted now names the operator's
51
+ cure, on the FIRST dead developer instead of the fourth (#285).** Measured by a peer session on a
52
+ live unattended run: one story's acceptance criterion required the EF migration to be *generated by
53
+ `dotnet ef`* in a workspace declaring `dotnet build` / `dotnet test`; four developers died and two
54
+ reviewer rounds ran over ~3 h, and the fourth wrote, verbatim, "dotnet ef is not grantable,
55
+ confirmed absent from .tldrx/workspace.yml:1 commands and refused twice already... No code changes
56
+ made this round" — the agent knew why it could not proceed, said so in plain words, and the system
57
+ bought a fifth attempt anyway. The field workaround was three exact-string slots added to
58
+ `workspace.yml` by hand, which a person had to deduce from four failures. That edit is now the
59
+ recorded reason: #278's classifier gains the case it had no name for, so a non-git refusal the
60
+ declared commands do not grant is no longer `unknown` with nothing to say but names the fix an
61
+ OPERATOR can apply — add a `commands:` slot whose value is exactly `dotnet ef`. The slot names the
62
+ tool and its subcommand, never the story's own arguments (`sha256sum s1.txt` asks for `sha256sum`,
63
+ not for a slot with one file baked into it), and the grant it is checked against is the real one:
64
+ `bashGrantsFor` writes `Bash(<declared>)` and `Bash(<declared> *)`, so `dotnet ef …` is ungranted
65
+ where `dotnet build` is declared even though both start with `dotnet`. That one notion lives beside
66
+ `DEVELOPER_GIT_VERBS` in `build/developerGrants.ts` and every reader calls it (§7). A `git` line is
67
+ never blamed on `commands:` — its allowance is that verb list, so "add a slot" would be a false
68
+ cure — and a caller that does not pass the declared commands classifies exactly as before, so every
69
+ sentence #278 shipped stays byte-identical. The story still blocks after one attempt with the same
70
+ exit code: #261's sentence is still the base, byte for byte, and the cure is the half it was
71
+ missing. **A Plan-time reader of acceptance PROSE was built for this too and measured OUT of the
72
+ change** — the signal that caught the field case went blind on the issue's own workspace, and the
73
+ signal that caught that one fired on `user profile` and `dotnet handles retries` — so it is filed
74
+ with both measurements as #290 instead of shipped half-working. A check that sometimes stays quiet
75
+ where it matters and sometimes shouts where it does not is worse than no check. The Definition of
76
+ Done, which is structured and run for real, has refused a command no slot declares since the
77
+ 2026-08-29 audit and is untouched here.
78
+
79
+ ## 0.19.0 — 2026-09-13
80
+
81
+ ### Added
82
+
83
+ - **`tldrx story reopen <id> --as-is --note "…"` settles a story a person finished BY HAND
84
+ from its branch as it stands, with no developer spawned (#279).** Measured on a real
85
+ unattended run at 0.18.2: S2's merge into its epic hit the #268 conflict, a person rebased
86
+ the branch by hand (DoD green, `git merge-tree` clean), and then there was no way to get that
87
+ branch merged. `story reopen` hands the story to a developer; the developer had nothing to
88
+ do; #271's rule — work is measured SINCE THE SPAWN — blocked the story after one attempt,
89
+ correctly, because work that already exists, older than the spawn, is indistinguishable from
90
+ a developer that did nothing. A second reopen buys the same outcome, so the only way out was
91
+ to invent a commit for the developer to make. This is the case that rule could not see, added
92
+ beside it and not carved out of it: `--as-is` spawns nothing at all, so there is no spawn to
93
+ measure work since. Everything after the missing developer is the path every other story
94
+ takes — the epic is merged in if it moved (#268), the DoD runs in the story's worktree, the
95
+ same reviewer judges the same diff, the same merge lands it. The worktree is found BY NAME
96
+ from the branch and reopened when the build had removed it, which is the ordinary case: a
97
+ blocked story's tree is pruned as it settles, and the hand fix is typically made in a scratch
98
+ worktree that is then removed. Two refusals are STRUCTURAL and no flag skips either, because
99
+ a verb that merges a branch nobody's agent wrote is exactly where a `--force` gets added at
100
+ 3 a.m. to unstick a run: the branch must carry at least one commit its epic has not already
101
+ got (`commitsBetween`, whose `null` stays "could not count" and refuses rather than reading
102
+ as "did not move", #273), and the DoD must go green under the same `dodProves` every other
103
+ story faces — the story blocks with the reason naming which. And the record does not lie
104
+ about who did the work (§7): `story.reopened` carries `reason: as_is` with the actor and the
105
+ note, `task.done` carries `as_is`/`as_is_by`/`as_is_note`, the review log's developer line
106
+ opens **none** and names the branch it took and the person who signed for it, and no task row
107
+ is written for a turn nothing was spawned for. The signature is cleared the moment a real
108
+ developer attempt starts, so a story requeued after a `changes` verdict over a hand-finished
109
+ branch records a DEVELOPER and not an as-is — found by review before it shipped, and pinned.
110
+ `--for-fix` and `--as-is` together are a usage error rather than a resolution in favour of
111
+ one: they answer different questions, and quietly performing the other is the CLI reporting
112
+ success for work it did not do. `tldrx next --prepare` refuses an `--as-is` story rather than
113
+ dispatching a developer bundle for it.
114
+
3
115
  ## 0.18.3 — 2026-09-13
4
116
 
5
117
  ### Fixed
package/README.md CHANGED
@@ -18,9 +18,13 @@ npm i -g tldr-experts # installs `tldrx` (short) and `tldr-experts` (same bi
18
18
  cd your-project
19
19
  tldrx doctor # check the environment — it is the authority, not a list in a README
20
20
  tldrx init # detect repos, map the code, write .tldrx/, ask only the gaps
21
- tldrx install --claude # write the skill, hooks and status line into ./.claude/
21
+ tldrx install --claude # write the skills, hooks and status line into ./.claude/
22
22
  ```
23
23
 
24
+ Planning a feature for an unattended run? **`/tldrx-plan`** (the second skill `install --claude`
25
+ writes) turns "I want X" into seed files that pass `tldrx seed check`, and ends with the exact
26
+ `run new` line.
27
+
24
28
  Later: **`tldrx update`** pulls the newest published version and prints the CHANGELOG between the
25
29
  one you had and the one you now have. Any command will tell you, in one line, when there is a newer
26
30
  one — off the hot path, cached for a day, silent when it cannot reach the registry, and never in
@@ -331,6 +335,8 @@ back on the registry is 0.3.0.
331
335
 
332
336
  | Version | Date | Status | Contains |
333
337
  |---|---|---|---|
338
+ | 0.20.0 | 2026-09-13 | `beta` | `tldrx seed check <file\|dir>` runs a hand-written seed through the same importer chain `run new --seed` runs, plus the authoring rules four unattended runs paid to learn — bullets under 200 characters, `[src:]` citations that resolve, `dod` lines byte-equal to a declared command with no shell separator, `depends_on` wherever two stories touch one file, a `Recommended:` on every open question — and prints the budget split and per-story caps a run would set, creating no run and spending nothing; `tldrx install --claude` now writes a second managed skill, `tldrx-plan`, that reads `workspace.yml` and the repo tree and turns "I want X" into seeds that pass the same check, naming only declared tools (#291). And a permission refusal over a command the workspace's `commands:` could have granted now names the operator's cure on the first dead developer instead of the fourth, measured on a live unattended run where four developers died and two review rounds ran before the missing command turned out to be one `workspace.yml` line away (#285). Minor release: a new CLI verb, `tldrx seed check`. |
339
+ | 0.19.0 | 2026-09-13 | `beta` | `tldrx story reopen <id> --as-is --note "…"` settles a story a person finished by hand from its branch as it stands, spawning no developer — measured on a live unattended run where a hand-rebased branch had a green DoD and a clean merge-tree but no way to land, blocked by #271's since-the-spawn rule from a developer with nothing to do (#279). Everything after the missing developer is the ordinary path: the epic merges in first if it moved, the same DoD and reviewer judge the diff, the same merge lands it. The record never lies about who did the work — `story.reopened` carries `reason: as_is` with the actor and note, `task.done` carries `as_is`/`as_is_by`/`as_is_note`, and the review log names the branch and the signer. Two refusals are structural with no flag to skip either: a branch with no commit ahead of its epic, and a red DoD. The signature clears the moment a real developer attempt starts, so a requeued story after a `changes` verdict records a developer, not an as-is. Minor release: a new flag, `--as-is`, on `story reopen`. |
334
340
  | 0.18.3 | 2026-09-13 | `beta` | four fixes to the unattended build path, all measured on live runs: a headless permission refusal is now classified — a chained shell command, a git verb outside the developer's allowance, or neither — so a chained line gets one retry with the cure stated first, an ungranted verb names its granted equivalent, and the developer prompt now lists the git verbs it holds from the one constant the grant is built from, after six refusals in one day left a ledger that recorded the symptom and not the cause; a wave no longer merges a story into its epic from the base it was cut from once a sibling has moved that epic — the story is measured against the epic tip immediately before merge, the epic is merged into the story and its Definition of Done re-run only when the epic actually moved, and a conflict blocks the story naming the files rather than merging half of one; a seed bullet over the claim cap no longer has its citation cut in half, with the clip moving back to the citation's start instead; and a failed commit count is no longer read as zero, so `--discard-pending` can no longer delete a plan just because git could not answer. |
335
341
  | 0.18.2 | 2026-09-13 | `beta` | three things measured on the first fully unattended run and on the live runs that followed it, one of them a regression 0.18.1 shipped hours earlier: `--ship merge` armed GitHub's auto-merge over a base that required nothing — the guard counted the checks the PR REPORTED while `--auto` waits on the base's REQUIREMENTS, so a proof run's pull request merged at 06:20:14 while all four of its checks finished between 06:21:38 and 06:24:56, and the record said `queued — GitHub merges when its checks pass`; ship now asks the base what it requires through rulesets and classic protection, names its three absences apart, and every unreadable answer arms nothing; the plan's per-story price had become a hard wall at 0.8x the planner's guess once 0.18.1 made those fields actually read, killing stories mid-flight at $1.28 and $3.25 against real costs an order of magnitude higher, so the ceiling is now `max(price x 3, $4.00)` derived at DISPATCH from the budget as it sits on disk — a run already in flight is covered without migrating anything — and, the half that carries the expensive end, a developer that dies on its cap with work in its tree commits it and lets the Definition of Done decide instead of parking the story, the same authority #271 gave a refused one; and the zero-touch recipe is written down where a person looks for it, seed file to backgrounded loop, on the README quick start and both documentation sites, with the honest boundary that this is the happy path without a person |
336
342
  | 0.18.1 | 2026-09-13 | `beta` | five things a run could not survive on its own, every one measured on the unattended proof runs that followed 0.18.0 rather than reasoned about: a priced plan was never priced — the planner wrote `stories[].estimate_usd` and Build read only `per_phase_usd` + `spent_usd`, so every story got the same $5.40 cap while the plan said $28, and the contract now names the shape and the plan check refuses a budget.yml that does not carry it; a headless refusal under a host-tokens ceiling wrote nothing to the ledger, so `--until-done` relaunched over a refusal it could not see, and now writes its `budget.blocked` first; a developer that had committed its work and was then refused a compound verification command was blocked BEFORE the facilitator ran the Definition of Done, so the DoD now decides when there is work and the refusal is recorded either way, with the prompt saying to run each DoD command verbatim and alone because shell separators split a line into subcommands that each need their own grant; a workspace can declare `<slot>_scoped` DoD commands that run per story on the paths it touched with the full suite once per epic head, after the full suite was measured running three times per story attempt; and a cancelled run no longer leaves an epic branch that refuses the ordinary retry — `run cancel` releases it and Build renames aside an epic whose owner run is closed, while an open or unknown owner still refuses verbatim and an uncounted branch is never deleted |