Skip to content

Releases: naiyixi/PureScience

案例市场索引(测试)

Pre-release

Choose a tag to compare

@naiyixi naiyixi released this 04 Nov 05:29

案例市场索引(测试)

这是案例市场的最小可用通道:一个索引文档 + 每个案例一个归档,都作为 release 资产发布。

  • case-marketplace.json — 索引本体(格式 purescience.case-marketplace v1)
  • internal-evaluation.tar.gz — 案例归档,内含 manifest.json 与 files/

归档摘要(SHA-256,索引里逐字钉住,下载端先对摘要再解包):

7a739d4c7d8372e84d831800551c61cfb824ce02fac7d732996b1c9fa4f16e9e  internal-evaluation.tar.gz

案例内容取自本机真实项目「内部评测」(6 个真实文件),不是示例工程。

PureScience v2.25.0

Choose a tag to compare

@github-actions github-actions released this 03 Nov 19:05

Maturity and Known Limitations

We label every capability the way we build it: ✅ shipped and verified on a real machine; 🚧 partly done, with the gap written next to it; 🗺️ planned. Each claim is traceable — a commit, a real-run log, or a record under docs/evidence/.

  • ✅ Shipped and machine-verified: This patch removes a false negative, not a defect. v2.21.3 fixed CodeBuddy’s probe PATH, but the post-install check still re-read the settings snapshot; with two instances sharing one storage root, settings-read measured 12,225 ms (11,918 ms held), so the freshly written value was invisible and a working install was reported as missing — the path and version were in settings.json all along, which is how the detector was exonerated and the re-read convicted. The check now asks the detector directly. This version fixed the three things a user meets first. The home page became scrollable (it was min-h-svh inside a viewport-fixing shell, so the gallery hanging off the bottom could not be reached), the demos became this machine’s own projects rather than evidence cards — a plaza built from projects that have run at least one session, six most-recent first, one click to open, timestamps instead of a session count, the evidence cards kept behind a disclosure — and CodeBuddy’s “installed but reported missing” was traced to npm’s #!/usr/bin/env node shim needing the node beside it: with a GUI-shaped PATH the probe got env: node: No such file or directory, so the binary’s own directory now goes on the probe’s PATH, and the installer verifies by probing instead of trusting npm’s exit code. ⌘⇧E expands or collapses every settled turn at once, writing the same per-group overrides a click writes. Open and named: search and native find still cannot reveal folded content, the connector panel’s domain sections cannot collapse, the plaza does not yet judge which runs went well, and the installer’s 277 MB composition is unmeasured. This version added four connectors and two numbers the panel had never stated. Two of those connectors were measured on this machine against the live services (LIPID MAPS: pubchem_cid=5997 → LMST01010001, C27H46O, 386.354866, with a name lookup refused by name because that API has none; OmniPath: directed interactions plus annotations plus enzyme→substrate edges, where /annotations turned out to reject organisms and the result now says so instead of pretending). Two were not: every TCIA address answers 000 from here and search.foldseek.com is intermittent, so those readings are taken by a live probe on the CI runner and printed into its job log — the connectors ship with that gap named rather than with a claim this machine cannot support. Structure similarity also required a real capability: RCSB's public search has no working structure service (service:"structure" → 400 for every entry_id shape, 500 for value, while chemical → 204), so the tool uploads coordinates to FoldSeek through a new postForm transport. The connector panel now names each row's scientific area, groups the directory by area in place, and states 35 connectors · 290 tools from the registry. Notebook kernels can only write where they were told: a seatbelt profile denies writes first, allows the session and figures directories and the temp trees back, then denies the managed runtime last (last match wins) — measured as WROTE inside, PermissionError outside, PermissionError inside the runtime even under an allowed temp tree. Open and named: shell and background jobs are not confined, Linux and Windows have no write guard and claim none, and the packaged-lane screening certifications run again (p0 109 passed / 12 skipped in 31.5 min) after the first-window budget went 30 s → 180 s. This version made the gallery's own claims harder to fake, and fixed the instrument that looks at the packaged lane. Three cards joined the home page (an import verdict you can recompute, four turns on one screen, a remote import refused), each holding readings and quotes that must appear verbatim in its named evidence file, with nine-language copy and rerun paths that have to exist. The packaged-lane checks that four certifications sit behind were only ever measured as 1 skipped; PURESCIENCE_E2E_PACKAGED_SKIP_BYPASS=1 now runs them and reproduces the failure here (1 failed), and the fixture writes its transcript into test-results/ because the app hands its agent a sanitised environment — the previous env-only path never reached the child. Three days of incidents are recorded entry by entry, and what is still broken stays on the label: the packaged screening lane still stalls at 0/N behind four named skips, the connector panel still groups by curation rather than discipline (35 connectors, 290 tools), and a cold start this file once put at 51.8 s measures 2.26 s to first window here against 3.20 s for the reference build on the same machine (three cold runs each, re-measured 2026-11-03) — that earlier number is withdrawn, not optimised around. This version made what leaves the app come back with its own receipts, and made a long session readable. The same session exported from the window, the web surface and the CLI produced a byte-identical payload — d36518b53a7d at 24 / 49 / 326 ms — with the whole-package digests differing only in exportedAt, because forging one timestamp to make three numbers agree would forge where the file came from; zip entries now carry a fixed 1980 epoch so the same content and stamp pack to the same bytes. An imported package recomputes its own claims: usage is derived from conversation.json and compared field by field (state: match, turns: 1, with turns that recorded nothing counted apart), tool readings judge the manifest's declaration against the bytes it shipped (absent:no-tool-calls stays a named absence, never "0 tool calls checked"), the verdict is written into the import record and compared there, and a remote import is refused outright (401, local-only-authority) rather than quietly allowed. A settled turn keeps its own 24 px summary row with its own token total, and the three inputs stay apart — a number, "usage not recorded", or no line at all, never a 0 — while the row still folds: on a real window two turns produced groups=2 with expanded: false then true, and four turns produced summaryRows:[24,24,24,24] in an 806 px viewport. That pair of readings took four attempts, and the reason is worth keeping: only one summary row ever appeared, and the cause was the deterministic test agent reusing the same tool-call ids every turn — the app correctly treated them as updates of the first turn's rows — so the product-side fix that shipped is the transcript merging the document's activity list with the live run's instead of letting the live run replace history. The CLI now serves an external MCP client: four read tools watched one audit line per call, then a write (archive_session) that resolves its target read-only, hangs the app's own approval card, and only then acts, refusing by name (not-approved, approval-unavailable, permission-gate-not-wired, already-archived) with the two ledgers paired by the same toolCallId — cancelling leaves the row untouched, approving writes archived and the client reads it back (2 passed, 18.3 s). The home page gained five use-case cards whose every number and quote must appear verbatim in its own evidence file — a reading drifting by a tenth of a second turns that guard red — with a copy control answered by the main process's clipboard bridge rather than the window's denied one. DOCX tables are now drawn from what the document declares instead of what the renderer assumed: the table's six edges read from tblBorders (falling back one level to tblStyle), applied by rendered geometry, a cell's own rules winning, and a table that declares nothing left untouched — a 3 pt green double frame over a 0.5 pt grey grid measured 3.21 px and 0.80 px on a real window. Along the way a real defect came out of a red lane rather than from reading code: the egress proxy's stop() waited forever when a client held its CONNECT tunnel open, which closeAllConnections does not cover. The previous version gave the wait a name and a price, and made the literature library check a retraction, follow citations both ways, and remember how far you read. Seven of the app's slowest requests were attributed from a week of its own log — 141 of 214 error/warn lines were slow IPC — before anything was changed. notebook:state re-parsed whole run documents on every read: on the real 60.1 MB file with 80 runs the hot median went 358.2 ms → 1.6 ms (cold 222.7 → 165.1) after an mtime+size cache that deliberately does not deep-copy, guarded by two tests that make the cache unable to lie. reviewer:get-for-session scanned two tables carrying only primary-key indexes behind an N+1 read and now has both indexes plus one query; notifications:get-snapshot queued its reads behind writes and no longer does; artifacts:read-preview was left alone on purpose, because an event-loop canary sampled at the same moment (261 ms against its 430 ms) accounts for most of it — rotation is reported rather than "fixed". sessions:save-session turned out to be two different slownesses: the 400 ms that dominated the samples was a database query in the post-write capture step (writeMs 3 ms, cpuShare 0), so it is skipped when no artifact version was finalised; the other half is a 60 MB document's write and rename (writeDiskMs 211, writeReplaceMs 176 ms) and is left at the I/O floor. settings:list-skills is the honest non-result: the log says 662 ms median while a full in-process call takes 50.8 ms cold and 11.0 ms hot over 67 real skills, so parallel reads and an mtime+size cache landed (11.0 → 8.1 ms, plus a skill list attribution line past 150 ms) and no target is claimed — without a baseline o...
Read more

PureScience v2.23.0

Choose a tag to compare

@github-actions github-actions released this 03 Nov 17:51

Maturity and Known Limitations

We label every capability the way we build it: ✅ shipped and verified on a real machine; 🚧 partly done, with the gap written next to it; 🗺️ planned. Each claim is traceable — a commit, a real-run log, or a record under docs/evidence/.

  • ✅ Shipped and machine-verified: This patch removes a false negative, not a defect. v2.21.3 fixed CodeBuddy’s probe PATH, but the post-install check still re-read the settings snapshot; with two instances sharing one storage root, settings-read measured 12,225 ms (11,918 ms held), so the freshly written value was invisible and a working install was reported as missing — the path and version were in settings.json all along, which is how the detector was exonerated and the re-read convicted. The check now asks the detector directly. This version fixed the three things a user meets first. The home page became scrollable (it was min-h-svh inside a viewport-fixing shell, so the gallery hanging off the bottom could not be reached), the demos became this machine’s own projects rather than evidence cards — a plaza built from projects that have run at least one session, six most-recent first, one click to open, timestamps instead of a session count, the evidence cards kept behind a disclosure — and CodeBuddy’s “installed but reported missing” was traced to npm’s #!/usr/bin/env node shim needing the node beside it: with a GUI-shaped PATH the probe got env: node: No such file or directory, so the binary’s own directory now goes on the probe’s PATH, and the installer verifies by probing instead of trusting npm’s exit code. ⌘⇧E expands or collapses every settled turn at once, writing the same per-group overrides a click writes. Open and named: search and native find still cannot reveal folded content, the connector panel’s domain sections cannot collapse, the plaza does not yet judge which runs went well, and the installer’s 277 MB composition is unmeasured. This version added four connectors and two numbers the panel had never stated. Two of those connectors were measured on this machine against the live services (LIPID MAPS: pubchem_cid=5997 → LMST01010001, C27H46O, 386.354866, with a name lookup refused by name because that API has none; OmniPath: directed interactions plus annotations plus enzyme→substrate edges, where /annotations turned out to reject organisms and the result now says so instead of pretending). Two were not: every TCIA address answers 000 from here and search.foldseek.com is intermittent, so those readings are taken by a live probe on the CI runner and printed into its job log — the connectors ship with that gap named rather than with a claim this machine cannot support. Structure similarity also required a real capability: RCSB's public search has no working structure service (service:"structure" → 400 for every entry_id shape, 500 for value, while chemical → 204), so the tool uploads coordinates to FoldSeek through a new postForm transport. The connector panel now names each row's scientific area, groups the directory by area in place, and states 35 connectors · 290 tools from the registry. Notebook kernels can only write where they were told: a seatbelt profile denies writes first, allows the session and figures directories and the temp trees back, then denies the managed runtime last (last match wins) — measured as WROTE inside, PermissionError outside, PermissionError inside the runtime even under an allowed temp tree. Open and named: shell and background jobs are not confined, Linux and Windows have no write guard and claim none, and the packaged-lane screening certifications run again (p0 109 passed / 12 skipped in 31.5 min) after the first-window budget went 30 s → 180 s. This version made the gallery's own claims harder to fake, and fixed the instrument that looks at the packaged lane. Three cards joined the home page (an import verdict you can recompute, four turns on one screen, a remote import refused), each holding readings and quotes that must appear verbatim in its named evidence file, with nine-language copy and rerun paths that have to exist. The packaged-lane checks that four certifications sit behind were only ever measured as 1 skipped; PURESCIENCE_E2E_PACKAGED_SKIP_BYPASS=1 now runs them and reproduces the failure here (1 failed), and the fixture writes its transcript into test-results/ because the app hands its agent a sanitised environment — the previous env-only path never reached the child. Three days of incidents are recorded entry by entry, and what is still broken stays on the label: the packaged screening lane still stalls at 0/N behind four named skips, the connector panel still groups by curation rather than discipline (35 connectors, 290 tools), and a cold start this file once put at 51.8 s measures 2.26 s to first window here against 3.20 s for the reference build on the same machine (three cold runs each, re-measured 2026-11-03) — that earlier number is withdrawn, not optimised around. This version made what leaves the app come back with its own receipts, and made a long session readable. The same session exported from the window, the web surface and the CLI produced a byte-identical payload — d36518b53a7d at 24 / 49 / 326 ms — with the whole-package digests differing only in exportedAt, because forging one timestamp to make three numbers agree would forge where the file came from; zip entries now carry a fixed 1980 epoch so the same content and stamp pack to the same bytes. An imported package recomputes its own claims: usage is derived from conversation.json and compared field by field (state: match, turns: 1, with turns that recorded nothing counted apart), tool readings judge the manifest's declaration against the bytes it shipped (absent:no-tool-calls stays a named absence, never "0 tool calls checked"), the verdict is written into the import record and compared there, and a remote import is refused outright (401, local-only-authority) rather than quietly allowed. A settled turn keeps its own 24 px summary row with its own token total, and the three inputs stay apart — a number, "usage not recorded", or no line at all, never a 0 — while the row still folds: on a real window two turns produced groups=2 with expanded: false then true, and four turns produced summaryRows:[24,24,24,24] in an 806 px viewport. That pair of readings took four attempts, and the reason is worth keeping: only one summary row ever appeared, and the cause was the deterministic test agent reusing the same tool-call ids every turn — the app correctly treated them as updates of the first turn's rows — so the product-side fix that shipped is the transcript merging the document's activity list with the live run's instead of letting the live run replace history. The CLI now serves an external MCP client: four read tools watched one audit line per call, then a write (archive_session) that resolves its target read-only, hangs the app's own approval card, and only then acts, refusing by name (not-approved, approval-unavailable, permission-gate-not-wired, already-archived) with the two ledgers paired by the same toolCallId — cancelling leaves the row untouched, approving writes archived and the client reads it back (2 passed, 18.3 s). The home page gained five use-case cards whose every number and quote must appear verbatim in its own evidence file — a reading drifting by a tenth of a second turns that guard red — with a copy control answered by the main process's clipboard bridge rather than the window's denied one. DOCX tables are now drawn from what the document declares instead of what the renderer assumed: the table's six edges read from tblBorders (falling back one level to tblStyle), applied by rendered geometry, a cell's own rules winning, and a table that declares nothing left untouched — a 3 pt green double frame over a 0.5 pt grey grid measured 3.21 px and 0.80 px on a real window. Along the way a real defect came out of a red lane rather than from reading code: the egress proxy's stop() waited forever when a client held its CONNECT tunnel open, which closeAllConnections does not cover. The previous version gave the wait a name and a price, and made the literature library check a retraction, follow citations both ways, and remember how far you read. Seven of the app's slowest requests were attributed from a week of its own log — 141 of 214 error/warn lines were slow IPC — before anything was changed. notebook:state re-parsed whole run documents on every read: on the real 60.1 MB file with 80 runs the hot median went 358.2 ms → 1.6 ms (cold 222.7 → 165.1) after an mtime+size cache that deliberately does not deep-copy, guarded by two tests that make the cache unable to lie. reviewer:get-for-session scanned two tables carrying only primary-key indexes behind an N+1 read and now has both indexes plus one query; notifications:get-snapshot queued its reads behind writes and no longer does; artifacts:read-preview was left alone on purpose, because an event-loop canary sampled at the same moment (261 ms against its 430 ms) accounts for most of it — rotation is reported rather than "fixed". sessions:save-session turned out to be two different slownesses: the 400 ms that dominated the samples was a database query in the post-write capture step (writeMs 3 ms, cpuShare 0), so it is skipped when no artifact version was finalised; the other half is a 60 MB document's write and rename (writeDiskMs 211, writeReplaceMs 176 ms) and is left at the I/O floor. settings:list-skills is the honest non-result: the log says 662 ms median while a full in-process call takes 50.8 ms cold and 11.0 ms hot over 67 real skills, so parallel reads and an mtime+size cache landed (11.0 → 8.1 ms, plus a skill list attribution line past 150 ms) and no target is claimed — without a baseline o...
Read more

PureScience v2.21.4

Choose a tag to compare

@github-actions github-actions released this 03 Nov 13:58

Maturity and Known Limitations

We label every capability the way we build it: ✅ shipped and verified on a real machine; 🚧 partly done, with the gap written next to it; 🗺️ planned. Each claim is traceable — a commit, a real-run log, or a record under docs/evidence/.

  • ✅ Shipped and machine-verified: This patch removes a false negative, not a defect. v2.21.3 fixed CodeBuddy’s probe PATH, but the post-install check still re-read the settings snapshot; with two instances sharing one storage root, settings-read measured 12,225 ms (11,918 ms held), so the freshly written value was invisible and a working install was reported as missing — the path and version were in settings.json all along, which is how the detector was exonerated and the re-read convicted. The check now asks the detector directly. This version fixed the three things a user meets first. The home page became scrollable (it was min-h-svh inside a viewport-fixing shell, so the gallery hanging off the bottom could not be reached), the demos became this machine’s own projects rather than evidence cards — a plaza built from projects that have run at least one session, six most-recent first, one click to open, timestamps instead of a session count, the evidence cards kept behind a disclosure — and CodeBuddy’s “installed but reported missing” was traced to npm’s #!/usr/bin/env node shim needing the node beside it: with a GUI-shaped PATH the probe got env: node: No such file or directory, so the binary’s own directory now goes on the probe’s PATH, and the installer verifies by probing instead of trusting npm’s exit code. ⌘⇧E expands or collapses every settled turn at once, writing the same per-group overrides a click writes. Open and named: search and native find still cannot reveal folded content, the connector panel’s domain sections cannot collapse, the plaza does not yet judge which runs went well, and the installer’s 277 MB composition is unmeasured. This version added four connectors and two numbers the panel had never stated. Two of those connectors were measured on this machine against the live services (LIPID MAPS: pubchem_cid=5997 → LMST01010001, C27H46O, 386.354866, with a name lookup refused by name because that API has none; OmniPath: directed interactions plus annotations plus enzyme→substrate edges, where /annotations turned out to reject organisms and the result now says so instead of pretending). Two were not: every TCIA address answers 000 from here and search.foldseek.com is intermittent, so those readings are taken by a live probe on the CI runner and printed into its job log — the connectors ship with that gap named rather than with a claim this machine cannot support. Structure similarity also required a real capability: RCSB's public search has no working structure service (service:"structure" → 400 for every entry_id shape, 500 for value, while chemical → 204), so the tool uploads coordinates to FoldSeek through a new postForm transport. The connector panel now names each row's scientific area, groups the directory by area in place, and states 35 connectors · 290 tools from the registry. Notebook kernels can only write where they were told: a seatbelt profile denies writes first, allows the session and figures directories and the temp trees back, then denies the managed runtime last (last match wins) — measured as WROTE inside, PermissionError outside, PermissionError inside the runtime even under an allowed temp tree. Open and named: shell and background jobs are not confined, Linux and Windows have no write guard and claim none, and the packaged-lane screening certifications run again (p0 109 passed / 12 skipped in 31.5 min) after the first-window budget went 30 s → 180 s. This version made the gallery's own claims harder to fake, and fixed the instrument that looks at the packaged lane. Three cards joined the home page (an import verdict you can recompute, four turns on one screen, a remote import refused), each holding readings and quotes that must appear verbatim in its named evidence file, with nine-language copy and rerun paths that have to exist. The packaged-lane checks that four certifications sit behind were only ever measured as 1 skipped; PURESCIENCE_E2E_PACKAGED_SKIP_BYPASS=1 now runs them and reproduces the failure here (1 failed), and the fixture writes its transcript into test-results/ because the app hands its agent a sanitised environment — the previous env-only path never reached the child. Three days of incidents are recorded entry by entry, and what is still broken stays on the label: the packaged screening lane still stalls at 0/N behind four named skips, the connector panel still groups by curation rather than discipline (35 connectors, 290 tools), and a measured 51.8 s cold start is unoptimised. This version made what leaves the app come back with its own receipts, and made a long session readable. The same session exported from the window, the web surface and the CLI produced a byte-identical payload — d36518b53a7d at 24 / 49 / 326 ms — with the whole-package digests differing only in exportedAt, because forging one timestamp to make three numbers agree would forge where the file came from; zip entries now carry a fixed 1980 epoch so the same content and stamp pack to the same bytes. An imported package recomputes its own claims: usage is derived from conversation.json and compared field by field (state: match, turns: 1, with turns that recorded nothing counted apart), tool readings judge the manifest's declaration against the bytes it shipped (absent:no-tool-calls stays a named absence, never "0 tool calls checked"), the verdict is written into the import record and compared there, and a remote import is refused outright (401, local-only-authority) rather than quietly allowed. A settled turn keeps its own 24 px summary row with its own token total, and the three inputs stay apart — a number, "usage not recorded", or no line at all, never a 0 — while the row still folds: on a real window two turns produced groups=2 with expanded: false then true, and four turns produced summaryRows:[24,24,24,24] in an 806 px viewport. That pair of readings took four attempts, and the reason is worth keeping: only one summary row ever appeared, and the cause was the deterministic test agent reusing the same tool-call ids every turn — the app correctly treated them as updates of the first turn's rows — so the product-side fix that shipped is the transcript merging the document's activity list with the live run's instead of letting the live run replace history. The CLI now serves an external MCP client: four read tools watched one audit line per call, then a write (archive_session) that resolves its target read-only, hangs the app's own approval card, and only then acts, refusing by name (not-approved, approval-unavailable, permission-gate-not-wired, already-archived) with the two ledgers paired by the same toolCallId — cancelling leaves the row untouched, approving writes archived and the client reads it back (2 passed, 18.3 s). The home page gained five use-case cards whose every number and quote must appear verbatim in its own evidence file — a reading drifting by a tenth of a second turns that guard red — with a copy control answered by the main process's clipboard bridge rather than the window's denied one. DOCX tables are now drawn from what the document declares instead of what the renderer assumed: the table's six edges read from tblBorders (falling back one level to tblStyle), applied by rendered geometry, a cell's own rules winning, and a table that declares nothing left untouched — a 3 pt green double frame over a 0.5 pt grey grid measured 3.21 px and 0.80 px on a real window. Along the way a real defect came out of a red lane rather than from reading code: the egress proxy's stop() waited forever when a client held its CONNECT tunnel open, which closeAllConnections does not cover. The previous version gave the wait a name and a price, and made the literature library check a retraction, follow citations both ways, and remember how far you read. Seven of the app's slowest requests were attributed from a week of its own log — 141 of 214 error/warn lines were slow IPC — before anything was changed. notebook:state re-parsed whole run documents on every read: on the real 60.1 MB file with 80 runs the hot median went 358.2 ms → 1.6 ms (cold 222.7 → 165.1) after an mtime+size cache that deliberately does not deep-copy, guarded by two tests that make the cache unable to lie. reviewer:get-for-session scanned two tables carrying only primary-key indexes behind an N+1 read and now has both indexes plus one query; notifications:get-snapshot queued its reads behind writes and no longer does; artifacts:read-preview was left alone on purpose, because an event-loop canary sampled at the same moment (261 ms against its 430 ms) accounts for most of it — rotation is reported rather than "fixed". sessions:save-session turned out to be two different slownesses: the 400 ms that dominated the samples was a database query in the post-write capture step (writeMs 3 ms, cpuShare 0), so it is skipped when no artifact version was finalised; the other half is a 60 MB document's write and rename (writeDiskMs 211, writeReplaceMs 176 ms) and is left at the I/O floor. settings:list-skills is the honest non-result: the log says 662 ms median while a full in-process call takes 50.8 ms cold and 11.0 ms hot over 67 real skills, so parallel reads and an mtime+size cache landed (11.0 → 8.1 ms, plus a skill list attribution line past 150 ms) and no target is claimed — without a baseline of the same size, "we improved it" would stand in for "it is fast enough". An event-loop stall used to end at no-cpu-in-process, which is a measurement and not a cause: every record now carries `garbage-co...
Read more

PureScience v2.21.3

Choose a tag to compare

@github-actions github-actions released this 03 Nov 04:53

Maturity and Known Limitations

We label every capability the way we build it: ✅ shipped and verified on a real machine; 🚧 partly done, with the gap written next to it; 🗺️ planned. Each claim is traceable — a commit, a real-run log, or a record under docs/evidence/.

  • ✅ Shipped and machine-verified: This version fixed the three things a user meets first. The home page became scrollable (it was min-h-svh inside a viewport-fixing shell, so the gallery hanging off the bottom could not be reached), the demos became this machine’s own projects rather than evidence cards — a plaza built from projects that have run at least one session, six most-recent first, one click to open, timestamps instead of a session count, the evidence cards kept behind a disclosure — and CodeBuddy’s “installed but reported missing” was traced to npm’s #!/usr/bin/env node shim needing the node beside it: with a GUI-shaped PATH the probe got env: node: No such file or directory, so the binary’s own directory now goes on the probe’s PATH, and the installer verifies by probing instead of trusting npm’s exit code. ⌘⇧E expands or collapses every settled turn at once, writing the same per-group overrides a click writes. Open and named: search and native find still cannot reveal folded content, the connector panel’s domain sections cannot collapse, the plaza does not yet judge which runs went well, and the installer’s 277 MB composition is unmeasured. This version added four connectors and two numbers the panel had never stated. Two of those connectors were measured on this machine against the live services (LIPID MAPS: pubchem_cid=5997 → LMST01010001, C27H46O, 386.354866, with a name lookup refused by name because that API has none; OmniPath: directed interactions plus annotations plus enzyme→substrate edges, where /annotations turned out to reject organisms and the result now says so instead of pretending). Two were not: every TCIA address answers 000 from here and search.foldseek.com is intermittent, so those readings are taken by a live probe on the CI runner and printed into its job log — the connectors ship with that gap named rather than with a claim this machine cannot support. Structure similarity also required a real capability: RCSB's public search has no working structure service (service:"structure" → 400 for every entry_id shape, 500 for value, while chemical → 204), so the tool uploads coordinates to FoldSeek through a new postForm transport. The connector panel now names each row's scientific area, groups the directory by area in place, and states 35 connectors · 290 tools from the registry. Notebook kernels can only write where they were told: a seatbelt profile denies writes first, allows the session and figures directories and the temp trees back, then denies the managed runtime last (last match wins) — measured as WROTE inside, PermissionError outside, PermissionError inside the runtime even under an allowed temp tree. Open and named: shell and background jobs are not confined, Linux and Windows have no write guard and claim none, and the packaged-lane screening certifications run again (p0 109 passed / 12 skipped in 31.5 min) after the first-window budget went 30 s → 180 s. This version made the gallery's own claims harder to fake, and fixed the instrument that looks at the packaged lane. Three cards joined the home page (an import verdict you can recompute, four turns on one screen, a remote import refused), each holding readings and quotes that must appear verbatim in its named evidence file, with nine-language copy and rerun paths that have to exist. The packaged-lane checks that four certifications sit behind were only ever measured as 1 skipped; PURESCIENCE_E2E_PACKAGED_SKIP_BYPASS=1 now runs them and reproduces the failure here (1 failed), and the fixture writes its transcript into test-results/ because the app hands its agent a sanitised environment — the previous env-only path never reached the child. Three days of incidents are recorded entry by entry, and what is still broken stays on the label: the packaged screening lane still stalls at 0/N behind four named skips, the connector panel still groups by curation rather than discipline (35 connectors, 290 tools), and a measured 51.8 s cold start is unoptimised. This version made what leaves the app come back with its own receipts, and made a long session readable. The same session exported from the window, the web surface and the CLI produced a byte-identical payload — d36518b53a7d at 24 / 49 / 326 ms — with the whole-package digests differing only in exportedAt, because forging one timestamp to make three numbers agree would forge where the file came from; zip entries now carry a fixed 1980 epoch so the same content and stamp pack to the same bytes. An imported package recomputes its own claims: usage is derived from conversation.json and compared field by field (state: match, turns: 1, with turns that recorded nothing counted apart), tool readings judge the manifest's declaration against the bytes it shipped (absent:no-tool-calls stays a named absence, never "0 tool calls checked"), the verdict is written into the import record and compared there, and a remote import is refused outright (401, local-only-authority) rather than quietly allowed. A settled turn keeps its own 24 px summary row with its own token total, and the three inputs stay apart — a number, "usage not recorded", or no line at all, never a 0 — while the row still folds: on a real window two turns produced groups=2 with expanded: false then true, and four turns produced summaryRows:[24,24,24,24] in an 806 px viewport. That pair of readings took four attempts, and the reason is worth keeping: only one summary row ever appeared, and the cause was the deterministic test agent reusing the same tool-call ids every turn — the app correctly treated them as updates of the first turn's rows — so the product-side fix that shipped is the transcript merging the document's activity list with the live run's instead of letting the live run replace history. The CLI now serves an external MCP client: four read tools watched one audit line per call, then a write (archive_session) that resolves its target read-only, hangs the app's own approval card, and only then acts, refusing by name (not-approved, approval-unavailable, permission-gate-not-wired, already-archived) with the two ledgers paired by the same toolCallId — cancelling leaves the row untouched, approving writes archived and the client reads it back (2 passed, 18.3 s). The home page gained five use-case cards whose every number and quote must appear verbatim in its own evidence file — a reading drifting by a tenth of a second turns that guard red — with a copy control answered by the main process's clipboard bridge rather than the window's denied one. DOCX tables are now drawn from what the document declares instead of what the renderer assumed: the table's six edges read from tblBorders (falling back one level to tblStyle), applied by rendered geometry, a cell's own rules winning, and a table that declares nothing left untouched — a 3 pt green double frame over a 0.5 pt grey grid measured 3.21 px and 0.80 px on a real window. Along the way a real defect came out of a red lane rather than from reading code: the egress proxy's stop() waited forever when a client held its CONNECT tunnel open, which closeAllConnections does not cover. The previous version gave the wait a name and a price, and made the literature library check a retraction, follow citations both ways, and remember how far you read. Seven of the app's slowest requests were attributed from a week of its own log — 141 of 214 error/warn lines were slow IPC — before anything was changed. notebook:state re-parsed whole run documents on every read: on the real 60.1 MB file with 80 runs the hot median went 358.2 ms → 1.6 ms (cold 222.7 → 165.1) after an mtime+size cache that deliberately does not deep-copy, guarded by two tests that make the cache unable to lie. reviewer:get-for-session scanned two tables carrying only primary-key indexes behind an N+1 read and now has both indexes plus one query; notifications:get-snapshot queued its reads behind writes and no longer does; artifacts:read-preview was left alone on purpose, because an event-loop canary sampled at the same moment (261 ms against its 430 ms) accounts for most of it — rotation is reported rather than "fixed". sessions:save-session turned out to be two different slownesses: the 400 ms that dominated the samples was a database query in the post-write capture step (writeMs 3 ms, cpuShare 0), so it is skipped when no artifact version was finalised; the other half is a 60 MB document's write and rename (writeDiskMs 211, writeReplaceMs 176 ms) and is left at the I/O floor. settings:list-skills is the honest non-result: the log says 662 ms median while a full in-process call takes 50.8 ms cold and 11.0 ms hot over 67 real skills, so parallel reads and an mtime+size cache landed (11.0 → 8.1 ms, plus a skill list attribution line past 150 ms) and no target is claimed — without a baseline of the same size, "we improved it" would stand in for "it is fast enough". An event-loop stall used to end at no-cpu-in-process, which is a measurement and not a cause: every record now carries garbage-collection, fs-queue-saturated, cpu-in-process, unexplained or unmeasured, with unexplained naming the milliseconds it ruled out and unmeasured saying an instrument was missing — merging those two is how "nobody was watching" starts reading as "the machine was fine"; the GC observer and the thread-pool canary are started with the app rather than when a stall is noticed, and the 20 ms saturation threshold comes from 57 real canary samples (min 1 / median 24 / p90 180 / max 686 ms). The literature ...
Read more

Nightly (latest main)

Nightly (latest main) Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 03 Nov 19:53

Automated build of the latest main (10397fb).

⚠️ Unstable pre-release. macOS builds are ad-hoc signed (not notarized): on first launch
right-click → Open, or run xattr -dr com.apple.quarantine "<app>".

PureScience v2.21.2

Choose a tag to compare

@github-actions github-actions released this 02 Nov 13:45

Maturity and Known Limitations

We label every capability the way we build it: ✅ shipped and verified on a real machine; 🚧 partly done, with the gap written next to it; 🗺️ planned. Each claim is traceable — a commit, a real-run log, or a record under docs/evidence/.

  • ✅ Shipped and machine-verified: This version added four connectors and two numbers the panel had never stated. Two of those connectors were measured on this machine against the live services (LIPID MAPS: pubchem_cid=5997 → LMST01010001, C27H46O, 386.354866, with a name lookup refused by name because that API has none; OmniPath: directed interactions plus annotations plus enzyme→substrate edges, where /annotations turned out to reject organisms and the result now says so instead of pretending). Two were not: every TCIA address answers 000 from here and search.foldseek.com is intermittent, so those readings are taken by a live probe on the CI runner and printed into its job log — the connectors ship with that gap named rather than with a claim this machine cannot support. Structure similarity also required a real capability: RCSB's public search has no working structure service (service:"structure" → 400 for every entry_id shape, 500 for value, while chemical → 204), so the tool uploads coordinates to FoldSeek through a new postForm transport. The connector panel now names each row's scientific area, groups the directory by area in place, and states 35 connectors · 290 tools from the registry. Notebook kernels can only write where they were told: a seatbelt profile denies writes first, allows the session and figures directories and the temp trees back, then denies the managed runtime last (last match wins) — measured as WROTE inside, PermissionError outside, PermissionError inside the runtime even under an allowed temp tree. Open and named: shell and background jobs are not confined, Linux and Windows have no write guard and claim none, and the packaged-lane screening certifications run again (p0 109 passed / 12 skipped in 31.5 min) after the first-window budget went 30 s → 180 s. This version made the gallery's own claims harder to fake, and fixed the instrument that looks at the packaged lane. Three cards joined the home page (an import verdict you can recompute, four turns on one screen, a remote import refused), each holding readings and quotes that must appear verbatim in its named evidence file, with nine-language copy and rerun paths that have to exist. The packaged-lane checks that four certifications sit behind were only ever measured as 1 skipped; PURESCIENCE_E2E_PACKAGED_SKIP_BYPASS=1 now runs them and reproduces the failure here (1 failed), and the fixture writes its transcript into test-results/ because the app hands its agent a sanitised environment — the previous env-only path never reached the child. Three days of incidents are recorded entry by entry, and what is still broken stays on the label: the packaged screening lane still stalls at 0/N behind four named skips, the connector panel still groups by curation rather than discipline (35 connectors, 290 tools), and a measured 51.8 s cold start is unoptimised. This version made what leaves the app come back with its own receipts, and made a long session readable. The same session exported from the window, the web surface and the CLI produced a byte-identical payload — d36518b53a7d at 24 / 49 / 326 ms — with the whole-package digests differing only in exportedAt, because forging one timestamp to make three numbers agree would forge where the file came from; zip entries now carry a fixed 1980 epoch so the same content and stamp pack to the same bytes. An imported package recomputes its own claims: usage is derived from conversation.json and compared field by field (state: match, turns: 1, with turns that recorded nothing counted apart), tool readings judge the manifest's declaration against the bytes it shipped (absent:no-tool-calls stays a named absence, never "0 tool calls checked"), the verdict is written into the import record and compared there, and a remote import is refused outright (401, local-only-authority) rather than quietly allowed. A settled turn keeps its own 24 px summary row with its own token total, and the three inputs stay apart — a number, "usage not recorded", or no line at all, never a 0 — while the row still folds: on a real window two turns produced groups=2 with expanded: false then true, and four turns produced summaryRows:[24,24,24,24] in an 806 px viewport. That pair of readings took four attempts, and the reason is worth keeping: only one summary row ever appeared, and the cause was the deterministic test agent reusing the same tool-call ids every turn — the app correctly treated them as updates of the first turn's rows — so the product-side fix that shipped is the transcript merging the document's activity list with the live run's instead of letting the live run replace history. The CLI now serves an external MCP client: four read tools watched one audit line per call, then a write (archive_session) that resolves its target read-only, hangs the app's own approval card, and only then acts, refusing by name (not-approved, approval-unavailable, permission-gate-not-wired, already-archived) with the two ledgers paired by the same toolCallId — cancelling leaves the row untouched, approving writes archived and the client reads it back (2 passed, 18.3 s). The home page gained five use-case cards whose every number and quote must appear verbatim in its own evidence file — a reading drifting by a tenth of a second turns that guard red — with a copy control answered by the main process's clipboard bridge rather than the window's denied one. DOCX tables are now drawn from what the document declares instead of what the renderer assumed: the table's six edges read from tblBorders (falling back one level to tblStyle), applied by rendered geometry, a cell's own rules winning, and a table that declares nothing left untouched — a 3 pt green double frame over a 0.5 pt grey grid measured 3.21 px and 0.80 px on a real window. Along the way a real defect came out of a red lane rather than from reading code: the egress proxy's stop() waited forever when a client held its CONNECT tunnel open, which closeAllConnections does not cover. The previous version gave the wait a name and a price, and made the literature library check a retraction, follow citations both ways, and remember how far you read. Seven of the app's slowest requests were attributed from a week of its own log — 141 of 214 error/warn lines were slow IPC — before anything was changed. notebook:state re-parsed whole run documents on every read: on the real 60.1 MB file with 80 runs the hot median went 358.2 ms → 1.6 ms (cold 222.7 → 165.1) after an mtime+size cache that deliberately does not deep-copy, guarded by two tests that make the cache unable to lie. reviewer:get-for-session scanned two tables carrying only primary-key indexes behind an N+1 read and now has both indexes plus one query; notifications:get-snapshot queued its reads behind writes and no longer does; artifacts:read-preview was left alone on purpose, because an event-loop canary sampled at the same moment (261 ms against its 430 ms) accounts for most of it — rotation is reported rather than "fixed". sessions:save-session turned out to be two different slownesses: the 400 ms that dominated the samples was a database query in the post-write capture step (writeMs 3 ms, cpuShare 0), so it is skipped when no artifact version was finalised; the other half is a 60 MB document's write and rename (writeDiskMs 211, writeReplaceMs 176 ms) and is left at the I/O floor. settings:list-skills is the honest non-result: the log says 662 ms median while a full in-process call takes 50.8 ms cold and 11.0 ms hot over 67 real skills, so parallel reads and an mtime+size cache landed (11.0 → 8.1 ms, plus a skill list attribution line past 150 ms) and no target is claimed — without a baseline of the same size, "we improved it" would stand in for "it is fast enough". An event-loop stall used to end at no-cpu-in-process, which is a measurement and not a cause: every record now carries garbage-collection, fs-queue-saturated, cpu-in-process, unexplained or unmeasured, with unexplained naming the milliseconds it ruled out and unmeasured saying an instrument was missing — merging those two is how "nobody was watching" starts reading as "the machine was fine"; the GC observer and the thread-pool canary are started with the app rather than when a stall is noticed, and the 20 ms saturation threshold comes from 57 real canary samples (min 1 / median 24 / p90 180 / max 686 ms). The literature library grew three connected pieces: a retraction check reading four independent Crossref signals instead of only relation['is-retracted-by'] (which hit 0 of 12 sampled withdrawn works, which is why the old checker found nothing), with the winning signal and the check time stored on the reference and the export gate reading only what was already stored; citation discovery in both directions on live data, where one English record reports 83,700 citing works and reads 50 of them while the result says so (incomplete), four Chinese-source records return 47–50 citations each, and language: zh catches only 2 of 200 rows so it is not the criterion; and a three-state reading status (unread / reading / read) that survives a restart, filters the list, and counts what the text cites but you have not finished — where "reading" counts as unfinished, since only read is finished. Previously it made a framework selection stop being silently ignored: two hand-maintained whitelists listed three of four framework ids, so codebuddy survived the settings parser and vanished on the next read, and session persistence dropped it too. *...
Read more

PureScience v2.21.1

Choose a tag to compare

@github-actions github-actions released this 01 Nov 06:55

Maturity and Known Limitations

We label every capability the way we build it: ✅ shipped and verified on a real machine; 🚧 partly done, with the gap written next to it; 🗺️ planned. Each claim is traceable — a commit, a real-run log, or a record under docs/evidence/.

  • ✅ Shipped and machine-verified: This version made the gallery's own claims harder to fake, and fixed the instrument that looks at the packaged lane. Three cards joined the home page (an import verdict you can recompute, four turns on one screen, a remote import refused), each holding readings and quotes that must appear verbatim in its named evidence file, with nine-language copy and rerun paths that have to exist. The packaged-lane checks that four certifications sit behind were only ever measured as 1 skipped; PURESCIENCE_E2E_PACKAGED_SKIP_BYPASS=1 now runs them and reproduces the failure here (1 failed), and the fixture writes its transcript into test-results/ because the app hands its agent a sanitised environment — the previous env-only path never reached the child. Three days of incidents are recorded entry by entry, and what is still broken stays on the label: the packaged screening lane still stalls at 0/N behind four named skips, the connector panel still groups by curation rather than discipline (31 connectors, 282 tools), and a measured 51.8 s cold start is unoptimised. This version made what leaves the app come back with its own receipts, and made a long session readable. The same session exported from the window, the web surface and the CLI produced a byte-identical payload — d36518b53a7d at 24 / 49 / 326 ms — with the whole-package digests differing only in exportedAt, because forging one timestamp to make three numbers agree would forge where the file came from; zip entries now carry a fixed 1980 epoch so the same content and stamp pack to the same bytes. An imported package recomputes its own claims: usage is derived from conversation.json and compared field by field (state: match, turns: 1, with turns that recorded nothing counted apart), tool readings judge the manifest's declaration against the bytes it shipped (absent:no-tool-calls stays a named absence, never "0 tool calls checked"), the verdict is written into the import record and compared there, and a remote import is refused outright (401, local-only-authority) rather than quietly allowed. A settled turn keeps its own 24 px summary row with its own token total, and the three inputs stay apart — a number, "usage not recorded", or no line at all, never a 0 — while the row still folds: on a real window two turns produced groups=2 with expanded: false then true, and four turns produced summaryRows:[24,24,24,24] in an 806 px viewport. That pair of readings took four attempts, and the reason is worth keeping: only one summary row ever appeared, and the cause was the deterministic test agent reusing the same tool-call ids every turn — the app correctly treated them as updates of the first turn's rows — so the product-side fix that shipped is the transcript merging the document's activity list with the live run's instead of letting the live run replace history. The CLI now serves an external MCP client: four read tools watched one audit line per call, then a write (archive_session) that resolves its target read-only, hangs the app's own approval card, and only then acts, refusing by name (not-approved, approval-unavailable, permission-gate-not-wired, already-archived) with the two ledgers paired by the same toolCallId — cancelling leaves the row untouched, approving writes archived and the client reads it back (2 passed, 18.3 s). The home page gained five use-case cards whose every number and quote must appear verbatim in its own evidence file — a reading drifting by a tenth of a second turns that guard red — with a copy control answered by the main process's clipboard bridge rather than the window's denied one. DOCX tables are now drawn from what the document declares instead of what the renderer assumed: the table's six edges read from tblBorders (falling back one level to tblStyle), applied by rendered geometry, a cell's own rules winning, and a table that declares nothing left untouched — a 3 pt green double frame over a 0.5 pt grey grid measured 3.21 px and 0.80 px on a real window. Along the way a real defect came out of a red lane rather than from reading code: the egress proxy's stop() waited forever when a client held its CONNECT tunnel open, which closeAllConnections does not cover. The previous version gave the wait a name and a price, and made the literature library check a retraction, follow citations both ways, and remember how far you read. Seven of the app's slowest requests were attributed from a week of its own log — 141 of 214 error/warn lines were slow IPC — before anything was changed. notebook:state re-parsed whole run documents on every read: on the real 60.1 MB file with 80 runs the hot median went 358.2 ms → 1.6 ms (cold 222.7 → 165.1) after an mtime+size cache that deliberately does not deep-copy, guarded by two tests that make the cache unable to lie. reviewer:get-for-session scanned two tables carrying only primary-key indexes behind an N+1 read and now has both indexes plus one query; notifications:get-snapshot queued its reads behind writes and no longer does; artifacts:read-preview was left alone on purpose, because an event-loop canary sampled at the same moment (261 ms against its 430 ms) accounts for most of it — rotation is reported rather than "fixed". sessions:save-session turned out to be two different slownesses: the 400 ms that dominated the samples was a database query in the post-write capture step (writeMs 3 ms, cpuShare 0), so it is skipped when no artifact version was finalised; the other half is a 60 MB document's write and rename (writeDiskMs 211, writeReplaceMs 176 ms) and is left at the I/O floor. settings:list-skills is the honest non-result: the log says 662 ms median while a full in-process call takes 50.8 ms cold and 11.0 ms hot over 67 real skills, so parallel reads and an mtime+size cache landed (11.0 → 8.1 ms, plus a skill list attribution line past 150 ms) and no target is claimed — without a baseline of the same size, "we improved it" would stand in for "it is fast enough". An event-loop stall used to end at no-cpu-in-process, which is a measurement and not a cause: every record now carries garbage-collection, fs-queue-saturated, cpu-in-process, unexplained or unmeasured, with unexplained naming the milliseconds it ruled out and unmeasured saying an instrument was missing — merging those two is how "nobody was watching" starts reading as "the machine was fine"; the GC observer and the thread-pool canary are started with the app rather than when a stall is noticed, and the 20 ms saturation threshold comes from 57 real canary samples (min 1 / median 24 / p90 180 / max 686 ms). The literature library grew three connected pieces: a retraction check reading four independent Crossref signals instead of only relation['is-retracted-by'] (which hit 0 of 12 sampled withdrawn works, which is why the old checker found nothing), with the winning signal and the check time stored on the reference and the export gate reading only what was already stored; citation discovery in both directions on live data, where one English record reports 83,700 citing works and reads 50 of them while the result says so (incomplete), four Chinese-source records return 47–50 citations each, and language: zh catches only 2 of 200 rows so it is not the criterion; and a three-state reading status (unread / reading / read) that survives a restart, filters the list, and counts what the text cites but you have not finished — where "reading" counts as unfinished, since only read is finished. Previously it made a framework selection stop being silently ignored: two hand-maintained whitelists listed three of four framework ids, so codebuddy survived the settings parser and vanished on the next read, and session persistence dropped it too. and before that a windowless run used to stall where nobody could look, and the review that was supposed to audit it never started. start --no-open has no window to click a permission card in: a real task sat after its first gated tool call with no further event for six minutes. GET /api/v1/permissions and POST /api/v1/permissions/:id/approve (purescience permissions / purescience approve) now read and answer those cards through the same narrow Task view (acp:get-state / acp:respond-permission, 11 → 13 commands — without them the route exists and answers 500), and approving is a named authority, satisfy-approval, which a generic task context cannot exercise: "who approved this" is never abstracted into "automation". Auto-review moved from the renderer to main, because a window was its only trigger — two identical CLI runs, the one with a window open reviewed, the other recorded nothing. Both paths converge through the existing already-reviewed check, so a turn is reviewed once. That first version of the trigger read the session once and so never fired at all — the end_turn event lands before the session is written (~1.8 s later, measured), which left a finished CLI turn unaudited with a clean-looking log; it now waits out the write on a bounded schedule and reports unreadable rather than dropping a turn silently (v2.15.3, measured before/after on the same CLI channel: 0 review rows → 1, verdict pass). Also in this version: a review persists outside any default five-second transaction budget, names its failures in seven families (the raw text kept as evidence), and stops at 300 tool calls per session; a client reset on a tunnel is no longer an uncaughtException; artifact finalisation waits out a durability race with a bounded retry instead of failing t...
Read more

PureScience v2.21.0

Choose a tag to compare

@github-actions github-actions released this 31 Oct 16:33

Maturity and Known Limitations

We label every capability the way we build it: ✅ shipped and verified on a real machine; 🚧 partly done, with the gap written next to it; 🗺️ planned. Each claim is traceable — a commit, a real-run log, or a record under docs/evidence/.

  • ✅ Shipped and machine-verified: This version made what leaves the app come back with its own receipts, and made a long session readable. The same session exported from the window, the web surface and the CLI produced a byte-identical payload — d36518b53a7d at 24 / 49 / 326 ms — with the whole-package digests differing only in exportedAt, because forging one timestamp to make three numbers agree would forge where the file came from; zip entries now carry a fixed 1980 epoch so the same content and stamp pack to the same bytes. An imported package recomputes its own claims: usage is derived from conversation.json and compared field by field (state: match, turns: 1, with turns that recorded nothing counted apart), tool readings judge the manifest's declaration against the bytes it shipped (absent:no-tool-calls stays a named absence, never "0 tool calls checked"), the verdict is written into the import record and compared there, and a remote import is refused outright (401, local-only-authority) rather than quietly allowed. A settled turn keeps its own 24 px summary row with its own token total, and the three inputs stay apart — a number, "usage not recorded", or no line at all, never a 0 — while the row still folds: on a real window two turns produced groups=2 with expanded: false then true, and four turns produced summaryRows:[24,24,24,24] in an 806 px viewport. That pair of readings took four attempts, and the reason is worth keeping: only one summary row ever appeared, and the cause was the deterministic test agent reusing the same tool-call ids every turn — the app correctly treated them as updates of the first turn's rows — so the product-side fix that shipped is the transcript merging the document's activity list with the live run's instead of letting the live run replace history. The CLI now serves an external MCP client: four read tools watched one audit line per call, then a write (archive_session) that resolves its target read-only, hangs the app's own approval card, and only then acts, refusing by name (not-approved, approval-unavailable, permission-gate-not-wired, already-archived) with the two ledgers paired by the same toolCallId — cancelling leaves the row untouched, approving writes archived and the client reads it back (2 passed, 18.3 s). The home page gained five use-case cards whose every number and quote must appear verbatim in its own evidence file — a reading drifting by a tenth of a second turns that guard red — with a copy control answered by the main process's clipboard bridge rather than the window's denied one. DOCX tables are now drawn from what the document declares instead of what the renderer assumed: the table's six edges read from tblBorders (falling back one level to tblStyle), applied by rendered geometry, a cell's own rules winning, and a table that declares nothing left untouched — a 3 pt green double frame over a 0.5 pt grey grid measured 3.21 px and 0.80 px on a real window. Along the way a real defect came out of a red lane rather than from reading code: the egress proxy's stop() waited forever when a client held its CONNECT tunnel open, which closeAllConnections does not cover. The previous version gave the wait a name and a price, and made the literature library check a retraction, follow citations both ways, and remember how far you read. Seven of the app's slowest requests were attributed from a week of its own log — 141 of 214 error/warn lines were slow IPC — before anything was changed. notebook:state re-parsed whole run documents on every read: on the real 60.1 MB file with 80 runs the hot median went 358.2 ms → 1.6 ms (cold 222.7 → 165.1) after an mtime+size cache that deliberately does not deep-copy, guarded by two tests that make the cache unable to lie. reviewer:get-for-session scanned two tables carrying only primary-key indexes behind an N+1 read and now has both indexes plus one query; notifications:get-snapshot queued its reads behind writes and no longer does; artifacts:read-preview was left alone on purpose, because an event-loop canary sampled at the same moment (261 ms against its 430 ms) accounts for most of it — rotation is reported rather than "fixed". sessions:save-session turned out to be two different slownesses: the 400 ms that dominated the samples was a database query in the post-write capture step (writeMs 3 ms, cpuShare 0), so it is skipped when no artifact version was finalised; the other half is a 60 MB document's write and rename (writeDiskMs 211, writeReplaceMs 176 ms) and is left at the I/O floor. settings:list-skills is the honest non-result: the log says 662 ms median while a full in-process call takes 50.8 ms cold and 11.0 ms hot over 67 real skills, so parallel reads and an mtime+size cache landed (11.0 → 8.1 ms, plus a skill list attribution line past 150 ms) and no target is claimed — without a baseline of the same size, "we improved it" would stand in for "it is fast enough". An event-loop stall used to end at no-cpu-in-process, which is a measurement and not a cause: every record now carries garbage-collection, fs-queue-saturated, cpu-in-process, unexplained or unmeasured, with unexplained naming the milliseconds it ruled out and unmeasured saying an instrument was missing — merging those two is how "nobody was watching" starts reading as "the machine was fine"; the GC observer and the thread-pool canary are started with the app rather than when a stall is noticed, and the 20 ms saturation threshold comes from 57 real canary samples (min 1 / median 24 / p90 180 / max 686 ms). The literature library grew three connected pieces: a retraction check reading four independent Crossref signals instead of only relation['is-retracted-by'] (which hit 0 of 12 sampled withdrawn works, which is why the old checker found nothing), with the winning signal and the check time stored on the reference and the export gate reading only what was already stored; citation discovery in both directions on live data, where one English record reports 83,700 citing works and reads 50 of them while the result says so (incomplete), four Chinese-source records return 47–50 citations each, and language: zh catches only 2 of 200 rows so it is not the criterion; and a three-state reading status (unread / reading / read) that survives a restart, filters the list, and counts what the text cites but you have not finished — where "reading" counts as unfinished, since only read is finished. Previously it made a framework selection stop being silently ignored: two hand-maintained whitelists listed three of four framework ids, so codebuddy survived the settings parser and vanished on the next read, and session persistence dropped it too. and before that a windowless run used to stall where nobody could look, and the review that was supposed to audit it never started. start --no-open has no window to click a permission card in: a real task sat after its first gated tool call with no further event for six minutes. GET /api/v1/permissions and POST /api/v1/permissions/:id/approve (purescience permissions / purescience approve) now read and answer those cards through the same narrow Task view (acp:get-state / acp:respond-permission, 11 → 13 commands — without them the route exists and answers 500), and approving is a named authority, satisfy-approval, which a generic task context cannot exercise: "who approved this" is never abstracted into "automation". Auto-review moved from the renderer to main, because a window was its only trigger — two identical CLI runs, the one with a window open reviewed, the other recorded nothing. Both paths converge through the existing already-reviewed check, so a turn is reviewed once. That first version of the trigger read the session once and so never fired at all — the end_turn event lands before the session is written (~1.8 s later, measured), which left a finished CLI turn unaudited with a clean-looking log; it now waits out the write on a bounded schedule and reports unreadable rather than dropping a turn silently (v2.15.3, measured before/after on the same CLI channel: 0 review rows → 1, verdict pass). Also in this version: a review persists outside any default five-second transaction budget, names its failures in seven families (the raw text kept as evidence), and stops at 300 tool calls per session; a client reset on a tunnel is no longer an uncaughtException; artifact finalisation waits out a durability race with a bounded retry instead of failing the turn; a Session left running by a dead process is closed as interrupted at startup, and a Session that died between "plan approved" and "no longer waiting" comes back idle instead of showing an approval that already happened; a notebook kernel now leads its own process group on POSIX, so teardown is one kill(-pgid) instead of a pid walk that misses whatever forked mid-teardown and cannot see a child launchd adopted (the old path reported reaped: true on that), with the group claim checked against the kernel's real pgid and a named log when it does not match; external-source verification no longer fails every call (an empty response.url fell through ?? into Invalid URL:, and a redirect's three outcomes now have three answers); and the review locator no longer demands a hash the model had to guess — contentHash is optional, pinned to the frozen block, with expected/received named on a mismatch. Measured during the audit that produced this batch, on the 2.15.1 candidate build: a windowless review returning flagged across five checks, 26 real ...
Read more

PureScience v2.20.0

Choose a tag to compare

@github-actions github-actions released this 29 Oct 02:21

Maturity and Known Limitations

We label every capability the way we build it: ✅ shipped and verified on a real machine; 🚧 partly done, with the gap written next to it; 🗺️ planned. Each claim is traceable — a commit, a real-run log, or a record under docs/evidence/.

  • ✅ Shipped and machine-verified: Where the wait goes now has a name and a price, and the literature library can check a retraction, follow citations both ways and remember how far you read. Seven of the app's slowest requests were attributed from a week of its own log — 141 of 214 error/warn lines were slow IPC — before anything was changed. notebook:state re-parsed whole run documents on every read: on the real 60.1 MB file with 80 runs the hot median went 358.2 ms → 1.6 ms (cold 222.7 → 165.1) after an mtime+size cache that deliberately does not deep-copy, guarded by two tests that make the cache unable to lie. reviewer:get-for-session scanned two tables carrying only primary-key indexes behind an N+1 read and now has both indexes plus one query; notifications:get-snapshot queued its reads behind writes and no longer does; artifacts:read-preview was left alone on purpose, because an event-loop canary sampled at the same moment (261 ms against its 430 ms) accounts for most of it — rotation is reported rather than "fixed". sessions:save-session turned out to be two different slownesses: the 400 ms that dominated the samples was a database query in the post-write capture step (writeMs 3 ms, cpuShare 0), so it is skipped when no artifact version was finalised; the other half is a 60 MB document's write and rename (writeDiskMs 211, writeReplaceMs 176 ms) and is left at the I/O floor. settings:list-skills is the honest non-result: the log says 662 ms median while a full in-process call takes 50.8 ms cold and 11.0 ms hot over 67 real skills, so parallel reads and an mtime+size cache landed (11.0 → 8.1 ms, plus a skill list attribution line past 150 ms) and no target is claimed — without a baseline of the same size, "we improved it" would stand in for "it is fast enough". An event-loop stall used to end at no-cpu-in-process, which is a measurement and not a cause: every record now carries garbage-collection, fs-queue-saturated, cpu-in-process, unexplained or unmeasured, with unexplained naming the milliseconds it ruled out and unmeasured saying an instrument was missing — merging those two is how "nobody was watching" starts reading as "the machine was fine"; the GC observer and the thread-pool canary are started with the app rather than when a stall is noticed, and the 20 ms saturation threshold comes from 57 real canary samples (min 1 / median 24 / p90 180 / max 686 ms). The literature library grew three connected pieces: a retraction check reading four independent Crossref signals instead of only relation['is-retracted-by'] (which hit 0 of 12 sampled withdrawn works, which is why the old checker found nothing), with the winning signal and the check time stored on the reference and the export gate reading only what was already stored; citation discovery in both directions on live data, where one English record reports 83,700 citing works and reads 50 of them while the result says so (incomplete), four Chinese-source records return 47–50 citations each, and language: zh catches only 2 of 200 rows so it is not the criterion; and a three-state reading status (unread / reading / read) that survives a restart, filters the list, and counts what the text cites but you have not finished — where "reading" counts as unfinished, since only read is finished. Previously it made a framework selection stop being silently ignored: two hand-maintained whitelists listed three of four framework ids, so codebuddy survived the settings parser and vanished on the next read, and session persistence dropped it too. and before that a windowless run used to stall where nobody could look, and the review that was supposed to audit it never started. start --no-open has no window to click a permission card in: a real task sat after its first gated tool call with no further event for six minutes. GET /api/v1/permissions and POST /api/v1/permissions/:id/approve (purescience permissions / purescience approve) now read and answer those cards through the same narrow Task view (acp:get-state / acp:respond-permission, 11 → 13 commands — without them the route exists and answers 500), and approving is a named authority, satisfy-approval, which a generic task context cannot exercise: "who approved this" is never abstracted into "automation". Auto-review moved from the renderer to main, because a window was its only trigger — two identical CLI runs, the one with a window open reviewed, the other recorded nothing. Both paths converge through the existing already-reviewed check, so a turn is reviewed once. That first version of the trigger read the session once and so never fired at all — the end_turn event lands before the session is written (~1.8 s later, measured), which left a finished CLI turn unaudited with a clean-looking log; it now waits out the write on a bounded schedule and reports unreadable rather than dropping a turn silently (v2.15.3, measured before/after on the same CLI channel: 0 review rows → 1, verdict pass). Also in this version: a review persists outside any default five-second transaction budget, names its failures in seven families (the raw text kept as evidence), and stops at 300 tool calls per session; a client reset on a tunnel is no longer an uncaughtException; artifact finalisation waits out a durability race with a bounded retry instead of failing the turn; a Session left running by a dead process is closed as interrupted at startup, and a Session that died between "plan approved" and "no longer waiting" comes back idle instead of showing an approval that already happened; a notebook kernel now leads its own process group on POSIX, so teardown is one kill(-pgid) instead of a pid walk that misses whatever forked mid-teardown and cannot see a child launchd adopted (the old path reported reaped: true on that), with the group claim checked against the kernel's real pgid and a named log when it does not match; external-source verification no longer fails every call (an empty response.url fell through ?? into Invalid URL:, and a redirect's three outcomes now have three answers); and the review locator no longer demands a hash the model had to guess — contentHash is optional, pinned to the frozen block, with expected/received named on a mismatch. Measured during the audit that produced this batch, on the 2.15.1 candidate build: a windowless review returning flagged across five checks, 26 real approvals in the same run (PubMed / DOI / Wayback), three live fetch_source fetches (6,988 / 7,018 / 5,403 characters), and that run completed with its artifact written. Re-checked on the build of this commit: the app boots headless in 3 s and GET /api/v1/permissions answers 200 {"data":[]} with no window open — the failure that replaced was a 500 from that same route. The performance conclusion was wrong and the correction is the reading: the 118.9 s save peak and the 203 s projection panel were one process-level freeze, caught by an event-loop stall watchdog that samples from a second thread while the loop is stuck — withdrawn, not optimised around. Not done here: the read-only expression for built-in specialists.

  • ✅ Shipped and machine-verified: Batch removal is one write now: all of the ticked rows go, or none do. The previous version looped the single removal and said what that cost — a crash halfway could leave half the rows gone, and copy pruning decided row by row would depend on list order. This writes the register once and judges pruning against the sources that remain, so two sources sharing bytes clean up once and a surviving source never loses its copy. The change also changes what a refusal means, and the copy had to follow: an atomic batch that fails was not partly applied, so the sentence says the batch was not applied and nothing was removed — and the old "removed 3, 1 refused" string is deleted from all nine dictionaries, because a key describing a failure that can no longer happen is worse than no key. The armed-then-confirm step and page-scoped select-all stay: they guard against a human misclick, which has nothing to do with whether the batch is a loop. Measured: three registered, two ticked, armed, confirmed — 1 passed (7.4s), the unticked row still there. Sources can be removed in batches, without a new channel. One batch is N runs of the single removal, so copy pruning by reference and the verbatim refusal of a rejected row keep working exactly as they always did — a batch cannot become a shortcut around them. Three restraints: the first click only arms the action and a second confirms it, because this is the one control whose effect cannot be undone from the screen; select-all covers only the current page, since ticking rows nobody has looked at would decide on their behalf; and a row the store refuses stays where it is, with the reason shown verbatim. Measured: three registered, two ticked, armed and confirmed — 1 passed (5.4s), and the unticked source is still there. The trade this version made and names: a batch is not atomic, because it is N writes, so a crash halfway could leave some rows gone and some not. An atomic alternative (one write, pruning judged against what remains) was built and not adopted; the choice is recorded in the evidence file. Not done: no undo, paging is still client-side. Molecular dynamics on CPU, and an honest answer about reproducibility. GROMACS 2025.4 from conda-forge minimises crambin and runs 10 ps in seconds: 11 frames, 642 atoms, 303 K measured against a 300 K target, mean potential −2859.6 kJ/mol. The important finding is a negative one — the...

Read more