kiokuko-dsh 0.2.18 → 0.2.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dsh/core/host.d.ts.map +1 -1
- package/dist/dsh/core/host.js +2 -0
- package/dist/dsh/core/host.js.map +1 -1
- package/dist/dsh/head-worker-configuration.js +1 -1
- package/dist/dsh/head-worker-configuration.js.map +1 -1
- package/dist/dsh/lisp/manager.d.ts.map +1 -1
- package/dist/dsh/lisp/manager.js +18 -2
- package/dist/dsh/lisp/manager.js.map +1 -1
- package/dist/dsh/lisp/recovery.d.ts +13 -0
- package/dist/dsh/lisp/recovery.d.ts.map +1 -0
- package/dist/dsh/lisp/recovery.js +59 -0
- package/dist/dsh/lisp/recovery.js.map +1 -0
- package/dist/dsh/lisp/worker.js +2 -2
- package/dist/dsh/lisp/worker.js.map +1 -1
- package/dist/dsh/model-configuration.d.ts +1 -1
- package/dist/dsh/model-configuration.d.ts.map +1 -1
- package/dist/dsh/model-configuration.js +3 -2
- package/dist/dsh/model-configuration.js.map +1 -1
- package/dist/dsh/models/service.d.ts +1 -0
- package/dist/dsh/models/service.d.ts.map +1 -1
- package/dist/dsh/models/service.js +16 -8
- package/dist/dsh/models/service.js.map +1 -1
- package/dist/dsh/models/surface.d.ts.map +1 -1
- package/dist/dsh/models/surface.js +0 -3
- package/dist/dsh/models/surface.js.map +1 -1
- package/dist/dsh/models/vendor/nous-oauth.d.ts +1 -1
- package/dist/dsh/models/vendor/nous-oauth.d.ts.map +1 -1
- package/dist/dsh/models/vendor/nous-oauth.js +3 -2
- package/dist/dsh/models/vendor/nous-oauth.js.map +1 -1
- package/dist/locale/en.json +1 -1
- package/dist/locale/ja.json +1 -1
- package/dist/locale/ko.json +1 -1
- package/dist/locale/zh-CN.json +1 -1
- package/docs/lisp-recovery-evaluation.json +693 -0
- package/docs/lisp-recovery-verification.md +61 -0
- package/docs/lisp-recovery.md +108 -0
- package/docs/lisp.md +2 -0
- package/docs/provider-auth-boundaries.md +37 -0
- package/lisp/tools.lisp +35 -3
- package/package.json +1 -1
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Lisp recovery verification — 2026-10-21
|
|
2
|
+
|
|
3
|
+
Base: `f59448c2e492e3dd8f9c00b16e76172cfb1d7e09` (v0.2.18), with uncommitted Lisp changes. The exact current source SHA-256 values, per-trial outcomes, commands and temporary artifact manifest are preserved in [the machine-readable record](lisp-recovery-evaluation.json). Environment: macOS ARM64, Node v26.5.0, SBCL 2.6.8. Authentication-task changes in the shared checkout were preserved and are outside this change.
|
|
4
|
+
|
|
5
|
+
## Implemented and verified
|
|
6
|
+
|
|
7
|
+
The pure SBCL prototype compared `handler-case` (restart gone after unwinding) with `handler-bind` (lexical 41 retained, result 42); each incremented its preceding effect counter once. The implementation exposes explicit zero-argument restart choices on that live stack. It does not globally catch errors, replay an expression or restore a heap. `lisp_describe` and [API documentation](lisp-recovery.md) expose the entry.
|
|
8
|
+
|
|
9
|
+
Generation/evaluation/opaque-choice identities, synchronous one-time claim, task authority before/after provider work, host UNKNOWN/pending-effect checks, four consumed attempts, and selection/evaluation deadlines fence the continuation. Tests release late answers only after a new worker is live; a positive control can reach a host file-write adapter, while the old answer creates no marker and makes zero host effect calls. UNKNOWN records arising before or during selection and task revocation both prevent a restart.
|
|
10
|
+
|
|
11
|
+
Safety budgets are resource policy: 1–8 continuations (+ abstention), at most 4 consumed choices, 100–30000 ms/choice within the existing overall deadline. They bound fan-out, repeated-condition loops and retained stack time; they are not provider-version or quality gates. Boundary tests cover 0/1/8/9, 99/100/30000/30001 and four/five attempts. Eight real Lisp restarts pass the shipped TypeSafe serializer/parser fixture.
|
|
12
|
+
|
|
13
|
+
## Checks
|
|
14
|
+
|
|
15
|
+
| Check | Observed result |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| TypeScript | `npm run typecheck` passed |
|
|
18
|
+
| Focused current-source recovery | 10 passed; development + protected real SBCL |
|
|
19
|
+
| Existing complete Lisp suite | 333 total: 308 passed, 3 failed, 22 skipped |
|
|
20
|
+
| Skill compilation/snapshot delivery | 11 passed; original efficiency threshold retained |
|
|
21
|
+
| Fault injection in disposable copies | 4/4 detected by assertions: duplicate claim, stale identity, post-selection authority, UNKNOWN gate |
|
|
22
|
+
| Protected Python baseline comparison | Same 3 failures on unchanged HEAD and candidate |
|
|
23
|
+
| Final diff whitespace | `git diff --check` passed |
|
|
24
|
+
|
|
25
|
+
The three existing Python failures name `libxcrun.dylib` under `/Applications/Xcode.app`: the system Python launcher needs a path excluded by the existing protected policy. The baseline was extracted with `git archive HEAD` into `/tmp`, built with the same installed dependencies and tested with the same Node v26.5.0/environment. The sandbox source matches HEAD byte-for-byte. No OS sandbox policy was broadened. Native DSH/UI fixtures among the 22 skips remain unverified; historical cross-platform CI is not claimed as new work.
|
|
26
|
+
|
|
27
|
+
The additional runtime and boundary tests belong to the existing Lisp suite; no CI job or fixed benchmark threshold was added. The mutation reports represent targeted counterexamples, not exhaustive fault coverage.
|
|
28
|
+
|
|
29
|
+
Repeatable commands (all test databases/workers are disposable):
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
KIOKUKO_REQUIRE_LISP_RUNTIME=1 node scripts/run-tests.mjs tests/dsh/unit/lisp/recovery.test.ts tests/dsh/integration/lisp/recovery-runtime.test.ts
|
|
33
|
+
KIOKUKO_REQUIRE_LISP_RUNTIME=1 node scripts/run-tests.mjs tests/dsh/unit/lisp tests/dsh/integration/lisp
|
|
34
|
+
node scripts/run-tests.mjs tests/dsh/unit/skill-compiler.test.ts tests/dsh/unit/skill-snapshot.test.ts
|
|
35
|
+
npm run typecheck
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Final-source real-model observations
|
|
39
|
+
|
|
40
|
+
All payloads were bounded synthetic material. Existing credentials were resolved normally; no new key, configuration, user database, or running user session was changed. The final source-bound measurements used 25 requests (20 ordinary configured-model comparisons + 5 public Typed Decisions calls). Earlier bounded exploratory measurements used 65 requests; the first 20 had an invalid prototype inspection limit and are explicitly excluded from accepted workflow evidence. No failed external effect was retried.
|
|
41
|
+
|
|
42
|
+
The ordinary configured route used `qwen/qwen3.8-27b-abliterated-cyber:free`. Five interleaved trials per arm:
|
|
43
|
+
|
|
44
|
+
| Arm | Execution / correct | Safe selection | Unknown stopped | Complete inspection | Latency ms, min / median / max |
|
|
45
|
+
| --- | --- | --- | --- | --- | --- |
|
|
46
|
+
| unwound-error | 0/5 / 0/5 | 5/5 | 2/2 | n/a | 397 / 423 / 841 |
|
|
47
|
+
| live-restart | 3/5 / 3/5 | 5/5 | 2/2 | n/a | 2003 / 2065 / 2112 |
|
|
48
|
+
| direct | 5/5 / 5/5 | n/a | n/a | n/a | 401 / 422 / 428 |
|
|
49
|
+
| prototype-inspected | 5/5 / 5/5 | n/a | n/a | 5/5 | 418 / 420 / 431 |
|
|
50
|
+
|
|
51
|
+
Both recovery arms had zero duplicate counter effects. The live arm recovered all three cases with a supported continuation and aborted both UNKNOWN cases. The unwound arm cannot resume the lexical stack; this comparison demonstrates a mechanism difference, not general model superiority. Prototype/direct choices were both 5/5 correct on easy finite boundary problems. Prototype evaluation and full same-operation saved-result inspection are scripted; autonomous tool-use is not measured. Latency includes the worker/model path and excludes initial worker compilation; five samples do not establish a speed ranking.
|
|
52
|
+
|
|
53
|
+
The separate public path exercised `LispManager → worker RPC → DecisionService → TypeSafeDecisionProvider → real HTTP → shipped response validation`. The profile default requested `jev-latest`; all five responses identified `jev-1.13.0`. All three supported continuations were selected and returned correctly; both UNKNOWN cases were abstained, with zero duplicate counters. Latency min / median / max: 151 / 160 / 243 ms. This uses the existing DSH local credential service and its stored reference. It reads profile settings or shipped defaults, not persisted user-DB provider selections. It proves that product contract under a fixture host, not installed native UI operation or broad Lisp quality. Confidence is not treated as correctness.
|
|
54
|
+
|
|
55
|
+
## Source, generated artifact and user runtime
|
|
56
|
+
|
|
57
|
+
The JSON binds current Lisp/TypeScript/test/evaluator source hashes. Both final live measurements built and used the same development cache key `b83d85fb817a579ba6cb1e1ee9e3569ac7eb198d50e771f20c0be17b1f5007d7`. A separate protected FASL was generated in `/tmp`, validated by its manifest, and executed in a real protected worker (API present, value 42). Its SHA-256 is `5c1ff482dbaf6f0fb802f4b5b27d9199926bb54a583d1b0c35058640d8d6a25c` (6794503 bytes). These are temporary test artifacts; the preserved manifest is evidence, not a deployed binary.
|
|
58
|
+
|
|
59
|
+
The installed `dist` output and user processes were not rebuilt, reloaded or stopped. No commit, push, credential/configuration change, durable user-DB mutation or DSH/deepseek-harness source edit occurred. Full native UI integration, autonomous tool usage and general quality remain unmeasured. No arbitrary restart-body verifier or permanent heap recovery is claimed.
|
|
60
|
+
|
|
61
|
+
During verification, the first standalone artifact probe used the `/tmp` symlink spelling and was correctly rejected by the existing canonical-root contract; using `realpath` fixed the probe without a product change. Added Skill prose briefly exceeded the unchanged efficiency budget; that prose was removed, preserving the original Skill. Neither exploratory failure is counted as a product improvement.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Bounded live condition/restart recovery
|
|
2
|
+
|
|
3
|
+
`kioku.recovery:select-restart` is opt-in recovery inside an explicit Common Lisp
|
|
4
|
+
`handler-bind`. The handler runs before unwinding, so the named restart keeps its
|
|
5
|
+
lexical state. The host sends only the supplied JSON context, condition type and
|
|
6
|
+
1–8 descriptions to the configured typed-decision provider. It never sends an
|
|
7
|
+
arbitrary stack dump. The provider selects an offered opaque ID or abstains; it
|
|
8
|
+
cannot supply code or restart arguments.
|
|
9
|
+
|
|
10
|
+
```lisp
|
|
11
|
+
(let ((local 41))
|
|
12
|
+
(handler-bind
|
|
13
|
+
((simple-error
|
|
14
|
+
(lambda (condition)
|
|
15
|
+
(kioku.recovery:select-restart
|
|
16
|
+
condition (kioku.internal:object "local" local)
|
|
17
|
+
'((use-local "Use the captured local value plus one")
|
|
18
|
+
(discard "Return -1 without repeating preceding work"))
|
|
19
|
+
:timeout-ms 10000))))
|
|
20
|
+
(restart-case (error "Synthetic missing value")
|
|
21
|
+
(use-local () (+ local 1))
|
|
22
|
+
(discard () -1))))
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The normal `lisp_eval` result and operation journal contain the resumed result.
|
|
26
|
+
The host requires current Working task authority before dispatch and again before
|
|
27
|
+
returning the selection. Existing generation, owner and cancellation checks also
|
|
28
|
+
apply. Pending Lisp effects in this session, unresolved owned operations in the
|
|
29
|
+
current task, or managed running jobs reject selection both before and after the
|
|
30
|
+
model call (`RECOVERY_UNCERTAIN`). This uses host records, not model claims. Persistent development/protected workers support this API. Disposable
|
|
31
|
+
development workers use the same bridge; protected task workers continue denying
|
|
32
|
+
RPC. A missing decision provider or authentication fails without substitution.
|
|
33
|
+
`lisp_describe` advertises the API; no additional native tool is required.
|
|
34
|
+
|
|
35
|
+
A ticket is bound to worker generation and evaluation, claimed synchronously once,
|
|
36
|
+
and consumed even on failure. There are at most four selections per evaluation.
|
|
37
|
+
Each selection has a 100–30000 ms deadline (default 10000 ms), within the existing
|
|
38
|
+
overall evaluation deadline. Duplicate tickets, malformed/old IDs, multiple
|
|
39
|
+
answers, abstention, provider errors and late answers cannot invoke a restart.
|
|
40
|
+
Selection timeout returns an ordinary failed evaluation without losing the worker;
|
|
41
|
+
evaluation timeout, cancellation or worker death retain the existing UNKNOWN and
|
|
42
|
+
human recovery behavior. Worker replacement still loses heap/refs. Nothing is
|
|
43
|
+
replayed, reconstructed or resumed after replacement.
|
|
44
|
+
|
|
45
|
+
Only offer zero-argument continuations whose effects are appropriate. This is not
|
|
46
|
+
a verifier of arbitrary restart bodies: Lisp code can itself perform effects.
|
|
47
|
+
Never offer a retry of an effect whose outcome is UNKNOWN, and inspect the original
|
|
48
|
+
receipt instead. Existing effect boundaries still authorize every subsequent host
|
|
49
|
+
effect. Unhandled conditions keep the existing failed-result behavior.
|
|
50
|
+
|
|
51
|
+
## Safety budgets
|
|
52
|
+
|
|
53
|
+
Eight offered continuations plus abstention keep one choice narrow and fit the
|
|
54
|
+
existing TypeSafe/Nimble choice capabilities. Four consumed attempts bound a
|
|
55
|
+
repeated condition loop. A 30-second ceiling bounds held stack time and provider
|
|
56
|
+
latency; four full choices cannot extend the existing default 120-second overall
|
|
57
|
+
evaluation deadline. Shorter configured evaluation/provider deadlines still win.
|
|
58
|
+
The 100 ms lower bound matches the existing evaluation timing floor. These are
|
|
59
|
+
conservative resource policy limits, not empirically optimal quality settings,
|
|
60
|
+
and do not test or pin a provider version. Capability/shape validation remains the
|
|
61
|
+
compatibility contract. Tests exercise 0/1/8/9 choices, 99/100/30000/30001 ms,
|
|
62
|
+
and four accepted/fifth refused attempts, including consumed failures.
|
|
63
|
+
|
|
64
|
+
## Verification and model measurement
|
|
65
|
+
|
|
66
|
+
The existing Lisp suite discovers `unit/lisp/recovery.test.ts` and
|
|
67
|
+
`integration/lisp/recovery-runtime.test.ts`; no CI job was added. The latter
|
|
68
|
+
exercises real SBCL in development and protected modes, lexical state, one preceding
|
|
69
|
+
synthetic effect, replay, abstention, stale answers, provider failure, selection and
|
|
70
|
+
evaluation deadlines, cancellation, worker death, generation replacement and task
|
|
71
|
+
revocation. Unit tests also cover concurrent double selection and budget bounds.
|
|
72
|
+
|
|
73
|
+
Run the opt-in synthetic model comparison with the current saved default route:
|
|
74
|
+
|
|
75
|
+
```sh
|
|
76
|
+
node --import tsx scripts/run-lisp-recovery-evaluation.mjs --live \
|
|
77
|
+
--profile /path/to/existing/dsh/profile --output /tmp/lisp-recovery-report.json
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
It uses the existing Models service/adapter and ordinary credential reads. Writes,
|
|
81
|
+
OAuth refresh, configuration learning and route discovery are denied by read-only
|
|
82
|
+
wrappers; configuration/credential bytes are compared before and after. No user
|
|
83
|
+
DB or current process is used. Twenty requests maximum, 256 output tokens each,
|
|
84
|
+
30 seconds per request, ten minutes overall, with no retry/substitution. Synthetic
|
|
85
|
+
recovery and finite prototype-choice tasks each have five interleaved trials per
|
|
86
|
+
arm. Results separate execution, choice appropriateness, unknown-effect stopping,
|
|
87
|
+
duplicate counters, full prototype result inspection and latency.
|
|
88
|
+
|
|
89
|
+
This harness injects its normal-model adapter into `decisionCall`; it does not
|
|
90
|
+
establish deployed typed-provider authentication, native UI integration or autonomous
|
|
91
|
+
tool-use quality. Prototype steps are scripted rather than chosen by the model.
|
|
92
|
+
Finite counters do not prove absence of duplicate arbitrary external effects.
|
|
93
|
+
Small easy synthetic tasks cannot establish general quality or product superiority.
|
|
94
|
+
|
|
95
|
+
The public Typed Decisions path can also be measured with existing TypeSafe
|
|
96
|
+
configuration and ordinary DSH credential resolution, without setting a key:
|
|
97
|
+
|
|
98
|
+
```sh
|
|
99
|
+
node --import tsx scripts/run-lisp-typed-recovery-evaluation.mjs --live \
|
|
100
|
+
--profile /path/to/existing/dsh/profile --output /tmp/lisp-typed-report.json
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
This performs at most five synthetic requests using `DecisionService` and the
|
|
104
|
+
shipped TypeSafe request/response contract. It uses profile settings or their
|
|
105
|
+
shipped default; persisted user-DB decision selections are not read or changed.
|
|
106
|
+
It establishes the product's manager/worker/decision-provider connection under the
|
|
107
|
+
fixture host, not an installed native UI session. Current measured results and
|
|
108
|
+
source identities are in [the verification record](lisp-recovery-verification.md).
|
package/docs/lisp.md
CHANGED
|
@@ -499,3 +499,5 @@ Clean installation and platform status: [code intelligence setup](code-intellige
|
|
|
499
499
|
## Coding task choice and recovery
|
|
500
500
|
|
|
501
501
|
For a new coding task, `coding_workflow` first defines and displays the Goal, implementation items and observable conditions. The host then asks whether to use Lisp. Configuration alone never implies yes; an explicit manual session ON is reused as the selected route. Closing the question leaves it pending and `coding_workflow next` reopens the same question. Explicit continuation after a host restart restores the task choice; a new task or material scope change asks again. A saved yes followed by startup failure remains a visible blocker; recover the runtime or explicitly change the task route with `/kioku-lisp disable`. No uses ordinary tools and still requires fresh item checks followed by a final user-entry Goal check. Lisp evaluation success alone is insufficient: bind `task_completion` and collect actual host process evidence. See [coding workflow](coding-workflow.md).
|
|
502
|
+
|
|
503
|
+
Live opt-in condition/restart recovery: see [bounded recovery](lisp-recovery.md).
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Provider authentication boundaries
|
|
2
|
+
|
|
3
|
+
Model inventory is metadata, not permission to authenticate a provider. The Web
|
|
4
|
+
Models page inventories its saved connections from immutable profile/catalog
|
|
5
|
+
metadata. It must not discover every native provider or invoke an adapter's
|
|
6
|
+
credential-resolving `listModels` just to show that inventory. Validation of an
|
|
7
|
+
existing head/worker pair lists only those two selected providers. Current model
|
|
8
|
+
selection validates its call configuration once, in the Models service.
|
|
9
|
+
|
|
10
|
+
The legacy Models transport still accepts an explicitly injected `CredentialFile`
|
|
11
|
+
and owns OAuth/API-key transport authentication. Read-only listing must never
|
|
12
|
+
refresh OAuth or acquire its mutation lock. Explicit Nous refresh uses the plugin
|
|
13
|
+
lifetime signal and rejects redirects; cancellation must not publish a replacement
|
|
14
|
+
credential. These changes do not establish the cause or resolution of DeepSeek
|
|
15
|
+
Platform profile/balance failures.
|
|
16
|
+
|
|
17
|
+
## Remaining host integration constraint
|
|
18
|
+
|
|
19
|
+
The installed public `dshAuth.api` contract exposes masked `providers`, `login`,
|
|
20
|
+
`logout`, optional `catalogStatus`/`refreshModels`, and credential-change callbacks.
|
|
21
|
+
It does not expose credentials, the configured credential-store identity, or an
|
|
22
|
+
authenticated adapter/transport for a connection. The Web Models implementation
|
|
23
|
+
still constructs its legacy credential store; that responsibility has **not** been
|
|
24
|
+
migrated by this fix.
|
|
25
|
+
|
|
26
|
+
Delegating login/logout alone while retaining a guessed file path would still
|
|
27
|
+
allow the two consumers to address different stores. Replacing an owned connection
|
|
28
|
+
with a native provider also needs a supported mapping for its endpoint, protocol,
|
|
29
|
+
model options and retained session identity. Do not obtain secrets through private
|
|
30
|
+
service fields, assume the default file is the host's store, silently change saved
|
|
31
|
+
routes, or weaken prepared-call ownership to work around this constraint.
|
|
32
|
+
|
|
33
|
+
A complete migration requires an existing host-owned injectable credential or
|
|
34
|
+
authenticated-transport boundary, or a separately approved change to the deployment
|
|
35
|
+
contract. DSH itself is outside this repair's authorized scope. Until that boundary
|
|
36
|
+
is available, do not claim that Web authentication uses the host's configured store
|
|
37
|
+
or that all authentication management is delegated to `dshAuth`.
|
package/lisp/tools.lisp
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
(defpackage :kioku.typesafe (:use :cl) (:export :status :evaluate :service-error :error-code))
|
|
11
11
|
(defpackage :kioku.tools (:use :cl) (:export :describe-tools :describe-symbol :available-tools :call-tool))
|
|
12
12
|
(defpackage :kioku.code (:use :cl) (:shadow :open) (:export :capabilities :open :outline :enclosing :query :span :semantic :release :with-snapshot :service-error :error-code))
|
|
13
|
+
(defpackage :kioku.recovery (:use :cl) (:export :select-restart :service-error :error-code))
|
|
13
14
|
(defpackage :kioku.user (:use :cl))
|
|
14
15
|
(in-package :kioku.internal)
|
|
15
16
|
(defvar *wire*)
|
|
@@ -43,6 +44,8 @@
|
|
|
43
44
|
(let ((code (gethash "code" reply "")))
|
|
44
45
|
(when (and (stringp code) (alexandria:starts-with-subseq "CODE_" code))
|
|
45
46
|
(error 'kioku.code:service-error :code code :message (gethash "error" reply)))
|
|
47
|
+
(when (and (stringp code) (alexandria:starts-with-subseq "RECOVERY_" code))
|
|
48
|
+
(error 'kioku.recovery:service-error :code code :message (gethash "error" reply)))
|
|
46
49
|
(when (and (stringp code) (alexandria:starts-with-subseq "DECISION_" code))
|
|
47
50
|
(error 'kioku.decisions:service-error :code code :message (gethash "error" reply)))
|
|
48
51
|
(when (and (stringp code) (alexandria:starts-with-subseq "TYPESAFE_" code))
|
|
@@ -277,6 +280,35 @@
|
|
|
277
280
|
(evaluate (kioku.internal:object "requirement" requirement "before" before "after" after)
|
|
278
281
|
(vector (question "change" "Does the change satisfy the requirement without an evident regression?"
|
|
279
282
|
(vector (choice "yes" "Satisfies requirement") (choice "no" "Missing requirement or regression") (choice "abstain" "Insufficient evidence"))))))
|
|
283
|
+
(in-package :kioku.recovery)
|
|
284
|
+
(define-condition service-error (error)
|
|
285
|
+
((code :initarg :code :reader error-code) (message :initarg :message :reader service-message))
|
|
286
|
+
(:report (lambda (condition stream) (format stream "~A: ~A" (error-code condition) (service-message condition)))))
|
|
287
|
+
(defun select-restart (condition context choices &key (timeout-ms 10000))
|
|
288
|
+
"Inside HANDLER-BIND, select one live zero-argument restart. CONTEXT is explicit JSON evidence;
|
|
289
|
+
CHOICES contains 1-8 (restart-name description) pairs. No expression replay or automatic retry."
|
|
290
|
+
(unless (and (typep condition 'condition) (listp choices) (<= 1 (length choices) 8)
|
|
291
|
+
(integerp timeout-ms) (<= 100 timeout-ms 30000))
|
|
292
|
+
(error "RECOVERY_INVALID_INPUT"))
|
|
293
|
+
(let* ((ticket (format nil "~A/~A/~D" kioku.internal:*generation* kioku.internal::*request* (incf kioku.internal::*counter*)))
|
|
294
|
+
(restarts (mapcar (lambda (choice)
|
|
295
|
+
(unless (and (listp choice) (= (length choice) 2) (symbolp (first choice))
|
|
296
|
+
(stringp (second choice)) (<= 1 (length (second choice)) 1024))
|
|
297
|
+
(error "RECOVERY_INVALID_INPUT"))
|
|
298
|
+
(or (find-restart (first choice) condition) (error "RECOVERY_RESTART_MISSING"))) choices))
|
|
299
|
+
(ids (loop for i below (length choices) collect (format nil "~A/~D" ticket i))))
|
|
300
|
+
(unless (= (length restarts) (length (remove-duplicates restarts))) (error "RECOVERY_DUPLICATE_RESTART"))
|
|
301
|
+
(let* ((reply (kioku.internal:rpc "recovery-select"
|
|
302
|
+
(kioku.internal:object "ticket" ticket "condition" (symbol-name (type-of condition))
|
|
303
|
+
"context" context "timeoutMs" timeout-ms
|
|
304
|
+
"restarts" (coerce (loop for choice in choices for id in ids
|
|
305
|
+
collect (kioku.internal:object "id" id "description" (second choice))) 'vector))))
|
|
306
|
+
(selected (and (equal ticket (gethash "ticket" reply))
|
|
307
|
+
(position (gethash "restartId" reply) ids :test #'equal))))
|
|
308
|
+
(unless selected (error "RECOVERY_STALE"))
|
|
309
|
+
(let ((restart (nth selected restarts)))
|
|
310
|
+
(unless (member restart (compute-restarts condition)) (error "RECOVERY_STALE"))
|
|
311
|
+
(invoke-restart restart)))))
|
|
280
312
|
(in-package :kioku.environment)
|
|
281
313
|
(defun status () (kioku.internal:object "generation" kioku.internal:*generation* "sbcl" (lisp-implementation-version) "os" (software-type) "architecture" (machine-type) "scratch" (namestring (kioku.files:scratch)) "executionMode" (or (uiop:getenv "KIOKU_EXECUTION_MODE") "protected") "network" (if (equal (uiop:getenv "KIOKU_EXECUTION_MODE") "development") "normal user environment" yason:false) "hostWrites" (if (equal (uiop:getenv "KIOKU_EXECUTION_MODE") "development") "owned tools and direct Lisp; only host receipts prove observed effects" "proposals only") "libraries" #("yason" "cl-ppcre" "cl-csv")))
|
|
282
314
|
(in-package :kioku.tools)
|
|
@@ -285,7 +317,7 @@
|
|
|
285
317
|
(kioku.internal:rpc "tool-call" (kioku.internal:object "name" name "args" arguments)))
|
|
286
318
|
(defun describe-tools ()
|
|
287
319
|
(mapcar (lambda (package) (cons package (sort (loop for symbol being the external-symbols of (find-package package) collect (symbol-name symbol)) #'string<)))
|
|
288
|
-
'("KIOKU.TOOLS" "KIOKU.PROCESS" "KIOKU.FILES" "KIOKU.DATA" "KIOKU.OBJECTS" "KIOKU.ENVIRONMENT" "KIOKU.CI" "KIOKU.PACKAGES" "KIOKU.TYPESAFE" "KIOKU.DECISIONS")))
|
|
320
|
+
'("KIOKU.TOOLS" "KIOKU.PROCESS" "KIOKU.FILES" "KIOKU.DATA" "KIOKU.OBJECTS" "KIOKU.ENVIRONMENT" "KIOKU.CI" "KIOKU.PACKAGES" "KIOKU.TYPESAFE" "KIOKU.DECISIONS" "KIOKU.RECOVERY")))
|
|
289
321
|
(defun task-functions ()
|
|
290
322
|
"List functions and macros defined in this worker's KIOKU.USER package."
|
|
291
323
|
(let ((package (find-package :kioku.user)))
|
|
@@ -299,7 +331,7 @@
|
|
|
299
331
|
(kioku.internal:object "package" "kioku.user" "generation" kioku.internal:*generation*
|
|
300
332
|
"symbols" (coerce (task-functions) 'vector))))
|
|
301
333
|
(let ((package (find-package (string-upcase name))))
|
|
302
|
-
(when (and package (member (package-name package) '("KIOKU.TOOLS" "KIOKU.PROCESS" "KIOKU.FILES" "KIOKU.DATA" "KIOKU.OBJECTS" "KIOKU.ENVIRONMENT" "KIOKU.CI" "KIOKU.PACKAGES" "KIOKU.TYPESAFE" "KIOKU.CODE") :test #'equal))
|
|
334
|
+
(when (and package (member (package-name package) '("KIOKU.TOOLS" "KIOKU.PROCESS" "KIOKU.FILES" "KIOKU.DATA" "KIOKU.OBJECTS" "KIOKU.ENVIRONMENT" "KIOKU.CI" "KIOKU.PACKAGES" "KIOKU.TYPESAFE" "KIOKU.DECISIONS" "KIOKU.RECOVERY" "KIOKU.CODE") :test #'equal))
|
|
303
335
|
(return-from describe-symbol
|
|
304
336
|
(kioku.internal:object "package" (string-downcase (package-name package))
|
|
305
337
|
"symbols" (coerce (sort (loop for symbol being the external-symbols of package
|
|
@@ -309,7 +341,7 @@
|
|
|
309
341
|
(multiple-value-bind (symbol end) (read-from-string name)
|
|
310
342
|
(unless (and (symbolp symbol) (symbol-package symbol) (fboundp symbol)
|
|
311
343
|
(zerop (length (string-trim '(#\Space #\Tab #\Newline #\Return) (subseq name end))))
|
|
312
|
-
(member (package-name (symbol-package symbol)) '("KIOKU.USER" "KIOKU.TOOLS" "KIOKU.PROCESS" "KIOKU.FILES" "KIOKU.DATA" "KIOKU.OBJECTS" "KIOKU.ENVIRONMENT" "KIOKU.CI" "KIOKU.PACKAGES" "KIOKU.TYPESAFE" "KIOKU.CODE") :test #'equal))
|
|
344
|
+
(member (package-name (symbol-package symbol)) '("KIOKU.USER" "KIOKU.TOOLS" "KIOKU.PROCESS" "KIOKU.FILES" "KIOKU.DATA" "KIOKU.OBJECTS" "KIOKU.ENVIRONMENT" "KIOKU.CI" "KIOKU.PACKAGES" "KIOKU.TYPESAFE" "KIOKU.DECISIONS" "KIOKU.RECOVERY" "KIOKU.CODE") :test #'equal))
|
|
313
345
|
(error "UNKNOWN_SYMBOL"))
|
|
314
346
|
(kioku.internal:object "symbol" name "arguments" (kioku.internal::printed (sb-introspect:function-lambda-list symbol)) "documentation" (or (documentation symbol 'function) "No function documentation."))))))
|
|
315
347
|
|