mirror of
https://github.com/PerpetualSoftware/pad.git
synced 2026-10-25 22:10:25 +00:00
a5000faafb61c098c736559117559fca8ce150ec
8 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
2d8aedc9a4 |
fix(release): the changelog starts at the previous stable release by version, and its exclude filters match GitHub's hash-prefixed entries (TASK-3268) (#1626)
* fix(release): the changelog starts at the previous stable release by version, and its exclude filters match GitHub's hash-prefixed entries (TASK-3268) Two release-notes defects, measured with the pinned GoReleaser (v2.15.4) in a changelog-only dry run whose output for v0.16.0 is byte-identical to the published notes. Base: GoReleaser took the previous tag from git describe on the new tag's parent, which sees only tags on that ancestry. Releases are cut on release-X.Y.x branches, so v0.16.0 was built from v0.15.0-rc.1, and a tag cut from main now would describe back past v0.16.0: GitHub's compare reports 547 commits from there against 301 from v0.16.0, re-listing all of v0.16.0. release.yml now pins GORELEASER_PREVIOUS_TAG through scripts/release-previous-tag.sh (the highest stable tag below the current one by version; an RC gets the previous stable) and fails the run if none exists. Filters: with `use: github` every entry is "<sha>: <message>", so the message-anchored excludes never matched and v0.16.0 shipped 30 docs, test, ci and chore lines. The rule now allows the prefix, a scope, and a type list made only of excluded types (`docs,test(store):`). Dry run of v0.16.0 with both fixes: 230 entries become 200. Every one of the 30 removed is an excluded type, and nothing is added. Claude-Session: https://claude.ai/code/session_016PXRzXhokr61CLbbu3Txj9 * fix(release): a breaking change stays in the notes whatever its type (TASK-3268 codex r1) The exclude accepted `!` before the colon, so `chore!: ...` would have been dropped. Codex round 1, P2. The v0.16.0 dry run is unchanged at 200 entries; an RE2 matrix of 15 messages, each with and without the hash prefix, answers as intended. Claude-Session: https://claude.ai/code/session_016PXRzXhokr61CLbbu3Txj9 |
||
|
|
7512f5500b |
docs(decision): README decision-provider section, and the day-73 eval scripts with their recorded baseline (TASK-3123) (#1593)
* docs(decision): README decision-provider section, and the day-73 eval scripts with their recorded baseline (TASK-3123) Housekeeping for PLAN-3114 tranche 1; no behaviour change. - README: a Decision provider (optional) section covering what uses it, that answers are asynchronous, configuration precedence (config file, then the admin setting, then the environment; PAD_DECISION_PROVIDER=none as the operator off-switch), and exactly what leaves the box and where. - scripts/decision-eval/eval.py and eval2.py: the day-73 scripts, as run (standard library, raw systemone API, key read from TYPESAFE_API_KEY). A read and a pattern scan found no key or token literal. - scripts/decision-eval/README.md: what each script measures, how to run it, how to regenerate the corpora, and the day-73 baseline. A, B and D were recomputed from the saved result files with the scripts' own summary logic and match PLAN-3114 (D AUC 0.939; the B >=0.8 bucket 86.8%). C comes from PLAN-3114's trail. eval.py --dry-run over the saved corpora queues the same 360 items the day-73 run did. - scripts/decision-eval/.gitignore: the corpora are private workspace exports and the results embed their content, so neither can be committed; neither was. The CHANGELOG line is queued as DOC-3242 (draft highlights for the release after v0.15.0, per PLAYB-1160), since releases take their changelog from goreleaser and a highlights DOC. Claude-Session: https://claude.ai/code/session_016PXRzXhokr61CLbbu3Txj9 * docs(decision): the README section states what off, the triggers, server info and disabling actually do (TASK-3123, codex round 1) Codex fact-checked every claim against the code, and four were too broad. Off is not "every surface unchanged": the decisions list is empty and playbook match answers 404. Jobs are also queued by restore and by comment edit and delete (verified at items.go:614/3207/3437/5459 and comments.go:133/196/416), and a closed item's job is dropped at the tick. pad server info cannot see the admin setting. Disabling stops new calls without a restart, but an in-flight request may finish. The scripts README now says eval2.py runs at the top level. Claude-Session: https://claude.ai/code/session_016PXRzXhokr61CLbbu3Txj9 |
||
|
|
bf0631d22f |
feat(ops): health reports which web bundle is served, and install-refresh warns when it is not a clean build of the commit (TASK-3233) (#1583)
The binary's commit stamp says nothing about web/build: it is generated,
gitignored and embedded as it stands. A bundle built from uncommitted edits
(a negative-control build, BUG-3129) or left over from an older commit
therefore ships under a clean commit stamp, and nothing afterwards could say
which bundle a server served.
- The server digests the web FS it embeds (sha256 over each file's path and
content hash) once in SetWebUI. /api/v1/health reports it as an additive
`web: {sha256, files, source_commit?, source_dirty?}`.
- `vite build` writes build-source.json (the commit, and the count of
`git status` entries under web/) into static/, which SvelteKit copies into
the bundle. It never fails a build: with no git, both fields are null
("unknown"), never clean. The stamp is gitignored.
- install-refresh.sh step 7 logs the served bundle and WARNS when the stamp
is missing, when it was built with web/ dirty, or when web/ changed
between the stamp's commit and the expected one. A backend-only commit on
top of a bundle is correct and is not flagged. It warns after the
restart; it does not prevent it.
Claude-Session: https://claude.ai/code/session_016PXRzXhokr61CLbbu3Txj9
|
||
|
|
d4ec587de9 |
fix(cli): a CLI call during an install-refresh bounce waits for the refresh instead of auto-starting a server over it (BUG-3215) (#1544)
install-refresh.sh stops the server, installs, and restarts it with the
captured argv. Any pad CLI call in between found nothing answering and
auto-started a server of its own: the caller's binary, cwd and default
flags. That server held the port against the refresh's restart (day 79:
127.0.0.1:7777 went dark and the script exited 1).
- The script writes <DataDir>/refresh.lock {pid, port, deadline} by rename
before the stop and removes it in its EXIT trap, only while it is still
its own. The deadline is 10s + PAD_PROBE_TIMEOUT (30s by default).
- EnsureServer defers to a live marker for its own port (writer pid alive
AND deadline not passed): it polls health and never spawns. If the
writer is still alive past the deadline it errors naming the pid. A dead
writer, a passed deadline, another port or an unparseable file means
the marker is ignored.
- The script names a holder that took the port before the restart spawns
(and does not spawn it), and refuses success when the listener after
the probe is not the restart it spawned. A health probe answers for
whoever holds the address.
- The script-test dependency guard now reads every install_refresh*_test.go.
Claude-Session: https://claude.ai/code/session_01A3rXV7GDLAhBe9mL4V6z2m
|
||
|
|
b2bee3242f |
fix(scripts): install-refresh restores the server's own cwd and matches the running server by identity (BUG-3196) (#1512)
* fix(scripts): install-refresh restores the server's own cwd with its argv, refuses a deleted one, and matches the running server by identity rather than the built binary's name (BUG-3196) Claude-Session: https://claude.ai/code/session_01RYiqbqXmxQMoKHsGm8B77N * fix(scripts): one existence check refuses a deleted server cwd, naming the path without the kernel's suffix (BUG-3196) Claude-Session: https://claude.ai/code/session_01RYiqbqXmxQMoKHsGm8B77N * test(scripts): the no-/proc refresh test declares lsof, which now reads the server's cwd there (BUG-3196) Claude-Session: https://claude.ai/code/session_01RYiqbqXmxQMoKHsGm8B77N * test(scripts): the lsof dependency sits on the requireScriptDeps line the guard reads (BUG-3196) Claude-Session: https://claude.ai/code/session_01RYiqbqXmxQMoKHsGm8B77N * docs(make): the install target's guarantees include the restored cwd (BUG-3196) Claude-Session: https://claude.ai/code/session_01RYiqbqXmxQMoKHsGm8B77N * fix(scripts): the server's cwd is re-checked immediately before the stop, and the capture's limits are stated (BUG-3196) Claude-Session: https://claude.ai/code/session_01RYiqbqXmxQMoKHsGm8B77N * fix(scripts): a failed restart cd says what state it leaves, not that no server runs (BUG-3196) Claude-Session: https://claude.ai/code/session_01RYiqbqXmxQMoKHsGm8B77N * fix(scripts): an unreadable server cwd is refused naming what was read and its error, and the case is tested (BUG-3196) Claude-Session: https://claude.ai/code/session_01RYiqbqXmxQMoKHsGm8B77N |
||
|
|
45dddb8f8f |
fix(scripts): install-refresh replaces the server listening on its port, by pid, and leaves other pad servers running (BUG-3194) (#1504)
* fix(scripts): install-refresh replaces the server listening on its port, by pid, and leaves other pad servers running (BUG-3194) The script counted every `pad server start` on the box and refused on more than one, so a sibling seat's e2e server (a worktree binary on its own port) made the scripted refresh unusable whenever anyone ran e2e. Its stop was a system-wide `pkill -x`, which would also have killed that server and any `pad` CLI call in flight. The target is now the `server start` process listening on the port the server itself would resolve without a flag (PAD_PORT, config, 7777), read with ss or lsof. It is stopped by pid, after its argv is re-read and matched. Still refused: the port held by something that is not a captured server, several servers on it, or several servers and none on it. One server with nothing on the port is still that server. Claude-Session: https://claude.ai/code/session_01RYiqbqXmxQMoKHsGm8B77N * docs(make): the install caution names npm ci, the hazard that remains; the stop is no longer system-wide (BUG-3194) Claude-Session: https://claude.ai/code/session_01RYiqbqXmxQMoKHsGm8B77N * fix(scripts): refuse a foreign or unreadable listener on the port, re-check before each signal, keep empty trailing arguments (BUG-3194, codex round 1) Claude-Session: https://claude.ai/code/session_01RYiqbqXmxQMoKHsGm8B77N * fix(scripts): the one-server fallback needs an explicit --port, so a lone sibling server is never replaced (BUG-3194, codex round 2) Claude-Session: https://claude.ai/code/session_01RYiqbqXmxQMoKHsGm8B77N * docs(make): reflow the install comment (BUG-3194) Claude-Session: https://claude.ai/code/session_01RYiqbqXmxQMoKHsGm8B77N |
||
|
|
3b7665a469 |
chore(decision-eval): attention threshold eval — no threshold passes the pre-registered rule (TASK-3137) (#1424)
* chore(decision-eval): attention threshold eval through the production state builder (TASK-3137) The instrument and its recorded results. The pre-registered rule is met by no threshold on the production state, so AttentionThreshold is unchanged; the ablation shows the 70/70 labels are historical while production asks about open items in the present. See RESULTS.md. Claude-Session: https://claude.ai/code/session_01ByMjAhvdWgbAWWeGE9jwWd * chore(decision-eval): replay each item to its last open moment (TASK-3137) The lead-ruled instrument: BuildItemState over the item as of just before its first logged terminal transition (r1), and at filing (r0), with the same 140 labels. The pre-registered rule (P >= 90%, R >= 60% on r1) is met by no threshold, so AttentionThreshold is unchanged. RESULTS.md records the finding: collection-membership labels cannot see the transient human waits that a task at its last open moment really has. Claude-Session: https://claude.ai/code/session_01ByMjAhvdWgbAWWeGE9jwWd * test(models): classify the eval tool's generic decode site (TASK-3137) The BUG-2685 guard found the new scripts/decision-eval readJSON helper as an unclassified interface-destination decode. It decodes item, comment, history and activity dumps, never a collection definition. Claude-Session: https://claude.ai/code/session_01ByMjAhvdWgbAWWeGE9jwWd |
||
|
|
110045578c |
fix(build): make install proves what it installed and what it restarted (BUG-2897, TASK-2787) (#1272)
`make install` made three claims it did not check.
1. It brought the server back BY SIDE EFFECT -- `pad auth whoami` triggers
an auto-start, which does not know the killed process's argv. A server
running `--host 0.0.0.0` came back bound to the default host alone:
curl 127.0.0.1:7777 -> 000 while the LAN address -> 200, with the
process count and the version both reading correct (BUG-2897).
2. `cp` copied whatever was at the repo path, not what the invocation
built. Two sessions sharing the checkout interleave and the loser's
build is installed by the winner, every exit code green (TASK-2787).
3. "Server restarted." was printed after a command ending in `|| true`,
with no probe of any kind. Not "the wrong address went unverified" --
nothing was verified. Found reading the recipe; neither filing names it,
and it is what made the other two invisible.
The logic moves to scripts/install-refresh.sh for one reason above
readability: a script can be TESTED. internal/buildtools drives it against
a compiled stub `pad`, including the branches where a check must FAIL.
Recipe-inline logic is only exercisable by running `make install`, which
stops the developer's server -- a test nobody runs twice, which is how this
target accumulated three unverified claims.
The script checks OUTCOMES rather than steps: what got installed, and what
is answering afterwards. Two commit checks, deliberately, answering
different questions -- the ARTIFACT before the kill, so a wrong build costs
an error instead of an outage, and the DESTINATION after the copy, which is
the shared-path race TASK-2787 names. The restart uses the argv read from
/proc before the kill, and nothing is printed about a restart until the
server answers on BOTH 127.0.0.1 and the configured host (`--host 0.0.0.0`
resolving to loopback plus the primary LAN address, since 0.0.0.0 is a bind
spec, not something to curl).
Three defects were found in the fix itself, by its own tests and by the
first real run:
- The restart redirected to $HOME/.pad/server.log with nothing creating
that directory. On a fresh HOME the redirect fails, the server never
starts, and the probe reports "did not answer" -- true, and three steps
downstream. Invisible to every hand-run this script could have had,
because a developer's box has ~/.pad by luck of history.
- The post-copy check SURVIVED its mutant: both fixtures reported the same
version from source and destination, so the guard and its absence were
indistinguishable. Fixed by making the stub's version depend on its path.
- Comparing commits by equality rejected a healthy build. `git rev-parse
--short` returns the shortest UNAMBIGUOUS prefix, so its width grows with
the object database: the binary embedded `a3a1d58` and the Makefile
produced `a3a1d586` minutes later. Now a prefix comparison in either
direction, with a negative leg pinning that a genuinely different commit
of the same width is still refused.
Five mutants, each verified to compile, each detected by its own leg.
Verified end to end on the real box: captured `--host 0.0.0.0`, installed
|