tldr-experts 0.13.1 → 0.14.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 +115 -0
- package/README.md +3 -1
- package/dist/hooks/answer-capture.js +1 -1
- package/dist/hooks/session-start.js +1 -1
- package/dist/tldrx.js +653 -347
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- /package/dist/hooks/{chunk-fyr7f9t6.js → chunk-3ns54mnq.js} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,83 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
## 0.14.0 — 2026-09-09
|
|
5
|
+
|
|
6
|
+
### Added
|
|
7
|
+
|
|
8
|
+
- **`run auto` now closes an `agent` gate itself, over a note it wrote and had validated (#198).**
|
|
9
|
+
`gates_policy: agent` said who MAY sign a gate; nothing in the engine produced the evidence note
|
|
10
|
+
it is signed over. The only writer was the `tldrx gate template` skeleton a host session fills
|
|
11
|
+
in at a keyboard — so moving a run's gates to `agent` changed *who is permitted to sign* without
|
|
12
|
+
changing *whether the loop could keep going*, and an unattended run over an all-`agent` run still
|
|
13
|
+
stopped at every gate with exit 4. Measured on 0.13.1 against a real workspace: the owner ran
|
|
14
|
+
`tldrx run gates set what:agent / plan:agent / watch:agent`, whose own reply promises "an agent
|
|
15
|
+
may now close it", and the loop stopped at the next gate anyway.
|
|
16
|
+
It now spawns one bounded **gate signer** when a stage's checks have passed and its policy is
|
|
17
|
+
`agent`: the stage's own model and effort, a quarter of the stage's per-agent ceiling, a tool
|
|
18
|
+
allowance that reads anything and writes exactly one file (`.agent/<stage>/evidence.md`), and a
|
|
19
|
+
prompt carrying the stage's declared outputs, the seven `auto` conditions as measured, and the
|
|
20
|
+
§2.8 skeleton rendered by the same function `gate template` writes.
|
|
21
|
+
The important half is what did NOT change: the note goes through the unchanged
|
|
22
|
+
`approve --as-agent` path, so `verdict: sign` with every condition holding closes the gate under
|
|
23
|
+
the note's own `by:`, and a `refuse`, a note that does not validate, a signer that wrote nothing
|
|
24
|
+
and a signer that died are one outcome — pending for a person, with the reason named on stdout
|
|
25
|
+
and now in the `gate.requested` notification's summary. There is no path from the signer to an
|
|
26
|
+
approval the validator would not also have taken, and no flag turns it on: an `agent` policy is
|
|
27
|
+
already the owner's recorded decision, and a second opt-in would mean the policy never did what
|
|
28
|
+
it said. `human` gates are untouched and `--gate-agent` stays rendering-only.
|
|
29
|
+
The turn is recorded like any other (`agent.spawned` / `agent.result`, `role: gate-signer`, a
|
|
30
|
+
`run.yml` task row, a row in `tldrx cost`), and it runs BEFORE the stage moves to
|
|
31
|
+
`awaiting_gate` — measured while building this, the other order made the `--wait-gates`
|
|
32
|
+
heartbeat announce "a signature is waiting on you" while the engine's own signer was still
|
|
33
|
+
mid-turn, and a person signed the gate the engine was in the middle of signing, three runs out
|
|
34
|
+
of three.
|
|
35
|
+
|
|
36
|
+
### Changed
|
|
37
|
+
|
|
38
|
+
- **The pre-merge reviewer runs targeted tests, not the whole suite.** Measured over one fix
|
|
39
|
+
wave: the 4,200-test suite ran THREE times in series at ~10 min each — the implementer
|
|
40
|
+
(`AGENTS.md` §3 requires it), the reviewer, and `merge-wave.sh` (by design). Only the
|
|
41
|
+
reviewer's was avoidable, and it was avoidable because nothing had told it not to: the brief
|
|
42
|
+
said merely that it *may* run tests, so a fresh reviewer sensibly ran everything. It now says
|
|
43
|
+
the negative out loud — run only the test files that cover the diff, named from
|
|
44
|
+
`git diff --stat`, plus `bun run typecheck`, and **never** the full `bun test` — with the
|
|
45
|
+
reason attached, that the wave re-runs every gate on the MERGED tree, so the reviewer's run
|
|
46
|
+
verifies nothing the wave will not, on a tree that is not the one being merged. The rule is
|
|
47
|
+
in `.claude/skills/maintain/references/sub-agent-briefs.md`, where the reviewer reads it, and
|
|
48
|
+
stated once in the skill's §3 for the workflow reader.
|
|
49
|
+
- **`AGENTS.md` §2 now says a slash in a branch name is a directory.** The review-record gate
|
|
50
|
+
(#192) builds `.review/<branch>.md` from the branch name VERBATIM, so `fix/x` wants
|
|
51
|
+
`.review/fix/x.md` — a nested directory, not `.review/fix-x.md`. Learned from the gate's
|
|
52
|
+
first refusal in the wild, which cost five minutes to read. The canonical fact lives in §2;
|
|
53
|
+
the maintain skill cites it rather than restating it.
|
|
54
|
+
- **`ci` cancels a run a newer push has already superseded.** The workflow had no
|
|
55
|
+
`concurrency:` group, so every push started a run and none of them stopped. Measured over the
|
|
56
|
+
last week: 25 of 122 push-triggered runs began less than 10 minutes apart on a 5.2-minute
|
|
57
|
+
average, which is roughly an hour to two hours of runner time per week spent finishing
|
|
58
|
+
answers nobody would read. `ci.yml` now groups on `github.ref` with `cancel-in-progress`.
|
|
59
|
+
It weakens no gate: `ci` is not the release gate — `scripts/release-check.sh` runs the full
|
|
60
|
+
gates before anything is pushed and `publish.yml` re-runs them after the tag
|
|
61
|
+
(`docs/RELEASING.md`), and neither is touched here.
|
|
62
|
+
- **The docs deploy now fires on `src/cli/helpText.ts`.** `docs-site/scripts/gen-cli.ts`
|
|
63
|
+
generates the site's `reference/cli-flags.md` and `cli.md` from that one registry, but the
|
|
64
|
+
workflow's `paths:` filter never listed it — so a help-registry change landed on `main`,
|
|
65
|
+
deployed nothing, and the published CLI reference kept showing the previous surface. It went
|
|
66
|
+
stale exactly that way after this week's CLI changes. The filter is otherwise unchanged, and
|
|
67
|
+
a test now pins the entry rather than trusting the next reader to notice.
|
|
68
|
+
- **`publish.yml` depends on `ci`'s answer instead of recomputing it.** The release job ran
|
|
69
|
+
typecheck, tests and build as its own steps — a THIRD run of the same gates on the same sha,
|
|
70
|
+
after the local `release-check.sh --pre-push` and after `ci`. Measured: ~6.5 min a publish,
|
|
71
|
+
~14 publishes in a week, ~87 min/week of runner time to re-derive something the repo already
|
|
72
|
+
knew. Publish now refuses unless the `ci` workflow has a `success` run for `github.sha`,
|
|
73
|
+
polled for up to 15 minutes through the REST API with `head_sha` (never `gh run list
|
|
74
|
+
--commit`, which returns `[]` for minutes while the runs exist — `AGENTS.md` §4). Nothing is
|
|
75
|
+
weakened: the same gates still run, once, and the checks only publish can do — tag equals
|
|
76
|
+
`package.json`, already-on-the-registry, `release-check.sh --ci`, OIDC trusted publishing —
|
|
77
|
+
are untouched. A `cancelled` ci run fails by name with the remedy, because the new
|
|
78
|
+
`cancel-in-progress` can supersede a release commit's run; merges stay frozen during a
|
|
79
|
+
release, as they already were.
|
|
80
|
+
|
|
4
81
|
## 0.13.1 — 2026-09-08
|
|
5
82
|
|
|
6
83
|
### Fixed
|
|
@@ -35,6 +112,44 @@
|
|
|
35
112
|
|
|
36
113
|
### Added
|
|
37
114
|
|
|
115
|
+
- **`tldrx run auto --wait-gates <duration>` — the loop waits for a signature the way it
|
|
116
|
+
already waits for an answer (#197).** Measured on a real workspace the day the notify hook
|
|
117
|
+
first drove a run: the question loop closed itself — the hook delivered Q1, the owner
|
|
118
|
+
answered from his chat, and `run auto` printed `waited 132s … resuming` — and then the very
|
|
119
|
+
next thing the stage did was reach its human gate, where the same owner approved from the
|
|
120
|
+
same chat and the loop had already exited 4. Three human gates a feature run is three manual
|
|
121
|
+
re-launches the hook was supposed to make unnecessary. The cause was scoped, not accidental:
|
|
122
|
+
`--wait-answers` gates its whole wait on an open-question card, which is `null` when the park
|
|
123
|
+
is a gate, so the wait was never reached. `--wait-gates` is a sibling flag rather than a wider
|
|
124
|
+
`--wait-answers`, because the two parks are closed by different verbs and calling a signature
|
|
125
|
+
an "answer" would be the flag name lying about what a person did. Approved → the loop carries
|
|
126
|
+
on; rejected → it stops and prints the note, which is now its LAST line so the `run.failed`
|
|
127
|
+
payload carries it to the phone of whoever has to act on it; lapsed → exit 4 with the same
|
|
128
|
+
lines it always had, after one `gate.timeout` (new kind, `question.timeout`'s twin, carrying
|
|
129
|
+
the approve and reject lines, the gate's policy, `waited_ms`, and `cost_usd` only when this
|
|
130
|
+
loop is the one that measured it). Nothing is spent while it polls — it reads files — and
|
|
131
|
+
whether a gate is pending is read through `waitingFor`, the one derivation `tldrx run status`
|
|
132
|
+
and the dashboard already share, never a second copy. **It waits FOR a signature and never
|
|
133
|
+
produces one**: there is no engine-side signing in this loop, so a stage on
|
|
134
|
+
`gates_policy: agent` stops it exactly as a `human` one does and is waited on identically —
|
|
135
|
+
an owner who switched three gates to `agent` expecting the loop to carry on was measuring
|
|
136
|
+
who MAY sign, not that anything had. Both wait flags may be given together, and without the
|
|
137
|
+
flag a gate exits 4 on the spot exactly as before.
|
|
138
|
+
- **The heartbeat stops telling a waiting owner that nothing is waiting on him at a GATE.**
|
|
139
|
+
`--notify-every`'s `status` payload learned in 0.11.1 not to say "Nothing is waiting on you"
|
|
140
|
+
over a run parked on a question — the fix that exists because a heartbeat is believed — but
|
|
141
|
+
its parked-ness came from the blocking-question predicate alone, so a run parked on a
|
|
142
|
+
signature got `waiting_on: []` and the exact sentence the fix was written to prevent. A
|
|
143
|
+
pending gate is now named in `waiting_on_gate` (`<phase>/<stage>`) beside `gate_policy`, the
|
|
144
|
+
summary says the run is waiting for a person to sign that stage, and `command` is the literal
|
|
145
|
+
`tldrx approve` line — the same spelling `gate.requested` and every decision card use, now
|
|
146
|
+
one exported helper instead of four literals. `waiting_on_gate` is a SIBLING key rather than
|
|
147
|
+
a member of `waiting_on`: an adapter maps every id in `waiting_on` to `tldrx answer <id>`,
|
|
148
|
+
and a stage id there would make it build a command nobody can type. Both keys are absent when
|
|
149
|
+
no gate is pending, so a heartbeat over a moving run is byte-identical to the one it sent
|
|
150
|
+
before. `gate.requested` now names the policy too, so an owner reading it on a phone knows
|
|
151
|
+
whether he is signing a `human` gate or overriding an `agent` one.
|
|
152
|
+
|
|
38
153
|
- **`tldrx expert rescore [<name>] [--area <a>]` — score the knowledge you already paid for.**
|
|
39
154
|
Its sibling `recompute` is arithmetic over the evidence rows already in `competencies.yml`;
|
|
40
155
|
`rescore` RE-READS `knowledge/*.md` and derives their evidence again under today's rules. It
|
package/README.md
CHANGED
|
@@ -316,6 +316,7 @@ back on the registry is 0.3.0.
|
|
|
316
316
|
|
|
317
317
|
| Version | Date | Status | Contains |
|
|
318
318
|
|---|---|---|---|
|
|
319
|
+
| 0.14.0 | 2026-09-09 | `beta` | an `agent` gate the engine can actually close, and three computations of the same answer cut to one: `gates_policy: agent` named who MAY sign a gate but nothing in the engine produced the evidence note it is signed over — measured on 0.13.1, an owner ran `tldrx run gates set what:agent`, was told "an agent may now close it", and the loop stopped at the next gate anyway with exit 4 — so `run auto` now spawns one bounded **gate signer** when a stage's checks pass under an `agent` policy: the stage's own model and effort, a quarter of its per-agent ceiling, a tool allowance that reads anything and writes exactly one file, and a prompt carrying the stage's declared outputs, the seven `auto` conditions as measured and the §2.8 skeleton `gate template` itself renders — the note going through the UNCHANGED `approve --as-agent` path, so a refusal, a note that does not validate, a signer that wrote nothing and a signer that died are one outcome, pending for a person with the reason named on stdout and now in the `gate.requested` summary, and there is no flag to turn it on because an `agent` policy is already the owner's recorded decision; the turn is recorded like any other (`role: gate-signer`, a `run.yml` task row, a row in `tldrx cost`) and taken BEFORE the stage moves to `awaiting_gate`, because the other order had a person sign the gate the engine was mid-signing, three runs out of three; and the suite stops being run three times per change — the pre-merge reviewer now runs only the test files that cover its diff plus `typecheck`, never the full `bun test`, since the wave re-runs every gate on the MERGED tree anyway, `publish.yml` refuses unless `ci` has a `success` run for the same sha instead of recomputing typecheck/tests/build (~87 min/week of runner time, with a `cancelled` ci run failing by name and the remedy), `ci` cancels a run a newer push has already superseded (25 of 122 push runs began under 10 minutes apart), the docs deploy finally fires on `src/cli/helpText.ts` so a help-registry change stops deploying nothing while the published CLI reference goes stale, and `AGENTS.md` §2 now says out loud that a slash in a branch name is a directory, which is what the review-record gate builds |
|
|
319
320
|
| 0.13.1 | 2026-09-08 | `beta` | a stage prompt that opens by saying what to do: every stage prompt now leads with a generated brief — who the reader is, which stage of which run, that the template below is to be FILLED, the exact path of every declared output, and that a question goes in the questions file rather than back to an operator who is not there — because on a real workspace at 0.13.0 a What sub-agent read its 66,452-byte prompt, found no request in it, wrote none of its six declared outputs and asked what to do, $0.29 spent; the brief is generated from the same `outputs:` list `pending.json` records, so it cannot name a path the commit will not look for, and the failure was never a regression — the spliced citation grammar grew the stage section 5,007 B → 13,180 B and the missing instruction was finally outnumbered; and the `N runs are open` nudge, the one imperative-shaped sentence in that agent's window and the one it duly answered, stops reaching sub-agents at all — `spawnAgent` marks every child it spawns and `session-start` emits nothing when it sees the marker, an absent marker still being a human's session and behaving exactly as before |
|
|
320
321
|
| 0.13.0 | 2026-09-08 | `beta` | evidence a role expert can actually earn, and a review that leaves a record: `--mode full`'s runs pass mines `tldrx-work/**` while the domain gate judged every citation it produced against folders of code — measured at four role experts, **$9.47 and one evidence row**, and unfixable from the workspace because the single spelling the matcher would reach is the one `domainPaths()` drops — so the gate now treats the run record as in-domain for the file mined FROM it, scoped to the pass and never to the expert's `kind:` (a light file citing a handoff is still out of domain and still says so), two shipped role templates stop declaring `.tldrx/map/**` and `.tldrx/map/{repo}/gotchas.md` paths that matched nothing at all, and a pass that validated, spent money and earned zero rows now prints `the level did not move — $X.XX bought 0 evidence row(s)` with its reasons carried into `check.passed` instead of a silent ledger; `tldrx expert rescore` recovers what was already bought for $0 by re-reading `knowledge/*.md` under today's rules, dating rows by the knowledge file's own `trained_at` and never by the clock, with `rescored_at` additive beside `at` — its ABSENCE keeping the meaning every existing row had — and one `evidence.rescored` line per file it actually moved, so a free re-derivation can never be read as a paid turn; `scripts/merge-wave.sh` refuses a branch carrying no `.review/<branch>.md` with **exit 10**, its own code because `2` in that script is already "merge conflict", a stale record refusing rather than warning and staleness measured as "the code moved" rather than "the sha differs", since committing the record moves the head past exactly the sha it names; and the mutation check moves from the reviewer, whose allowance is `Read`/`Grep`/`Glob`/`Bash(git diff *)` and holds no pen, to the developer's contract that can run it, leaving the reviewer the read it can actually perform |
|
|
321
322
|
| 0.12.0 | 2026-09-08 | `beta` | records that can be attributed and spans that were actually measured: the reviewer can be pinned to its own model and effort per role (`reviewer:`) and per story stakes (`reviewer_by_stakes:`, keyed on a story's new optional `stakes:` enum), resolved field by field under `--model`/`--effort` and shipping NO opus default — because there is no evidence yet that a stronger reviewer finds more, only the record that lets the evidence accumulate: every verdict now names the model that produced it, a host review reading `basis: host-declared` off its own flags and a host that declared nothing reading `not recorded` rather than the bundle's suggestion; `run.yml` gains `created_with` and `last_written_by` beside the file format's own `version: 1`, and `agent.spawned`/`agent.result` carry `tldrx_version`, so a run that outlived an upgrade carries both ends of the range that drove it; a task row carries `duration_ms` that never travels without `duration_basis` — `spawned` is the wall clock around the sub-agent's process, `prepare-to-commit` is a ceiling that includes the host's own time — and `tldrx cost` shows a duration per attempt and a per-stage sum that names a mixed basis instead of adding two different quantities, with a pre-existing row reading `not recorded` and never `0s`; no surface prints a bare `$0.00` over work nobody metered — one implementation writes `≥ $12.40 (7 tasks unmetered)` or `not measured: 9 in-session tasks, 0 metered` across `run status`, `budget show`, the dashboard, `replay`, `run auto`, the Build handoff and every notification, and `budget.yml` gains `unmetered_tasks` and `spent_basis`; the surface a story actually changed is measured off its own diff over the range the reviewer was shown and appended as one `story.touches_widened` with `basis: "measured"` beside what was declared, advisory and never rewriting the operator's `touches:`; and a `maintain` skill encodes the maintenance circuit twelve hand-run waves actually measured — reproduce an issue on current `origin/main` before touching anything, a fresh reviewer before `merge-wave.sh` and not after, at most 3 issues and 2 implementers a cycle — pinned by a test that every command and `§N` it cites resolves |
|
|
@@ -347,7 +348,8 @@ path documented; `stable` = 1.0, semver from here on. The badge above shows the
|
|
|
347
348
|
**One command: `scripts/release.sh X.Y.Z --tag beta`.** The tag is not optional in practice: omit
|
|
348
349
|
`--tag` and the script writes `alpha`, which is no longer this project's status. It is the only
|
|
349
350
|
sanctioned path — a Claude Code hook denies hand-made `git tag` / `npm publish`, and `publish.yml`
|
|
350
|
-
runs `release-check.sh --ci` (the file checks only)
|
|
351
|
+
runs `release-check.sh --ci` (the file checks only) and refuses to publish unless the `ci`
|
|
352
|
+
workflow is already green for that exact sha.
|
|
351
353
|
Checklist and judgement calls: `docs/RELEASING.md`.
|
|
352
354
|
|
|
353
355
|
MIT, © 2026 Alan Martinez — a placeholder made while scaffolding; change it freely before anything ships.
|