@dsh-enhanced/assistant-skills 0.1.30

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.
Files changed (84) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +211 -0
  3. package/cordis.patch.yml +3 -0
  4. package/lib/capture-expansion.d.ts +18 -0
  5. package/lib/capture-expansion.d.ts.map +1 -0
  6. package/lib/capture-expansion.js +187 -0
  7. package/lib/capture-expansion.js.map +1 -0
  8. package/lib/comparison.d.ts +69 -0
  9. package/lib/comparison.d.ts.map +1 -0
  10. package/lib/comparison.js +173 -0
  11. package/lib/comparison.js.map +1 -0
  12. package/lib/definition.d.ts +163 -0
  13. package/lib/definition.d.ts.map +1 -0
  14. package/lib/definition.js +450 -0
  15. package/lib/definition.js.map +1 -0
  16. package/lib/external-holdout.d.ts +34 -0
  17. package/lib/external-holdout.d.ts.map +1 -0
  18. package/lib/external-holdout.js +212 -0
  19. package/lib/external-holdout.js.map +1 -0
  20. package/lib/holdout-authority.d.ts +123 -0
  21. package/lib/holdout-authority.d.ts.map +1 -0
  22. package/lib/holdout-authority.js +263 -0
  23. package/lib/holdout-authority.js.map +1 -0
  24. package/lib/holdout-cli.d.ts +4 -0
  25. package/lib/holdout-cli.d.ts.map +1 -0
  26. package/lib/holdout-cli.js +221 -0
  27. package/lib/holdout-cli.js.map +1 -0
  28. package/lib/holdout-qualification.d.ts +83 -0
  29. package/lib/holdout-qualification.d.ts.map +1 -0
  30. package/lib/holdout-qualification.js +306 -0
  31. package/lib/holdout-qualification.js.map +1 -0
  32. package/lib/index.d.ts +22 -0
  33. package/lib/index.d.ts.map +1 -0
  34. package/lib/index.js +9 -0
  35. package/lib/index.js.map +1 -0
  36. package/lib/prospective-holdout.d.ts +35 -0
  37. package/lib/prospective-holdout.d.ts.map +1 -0
  38. package/lib/prospective-holdout.js +254 -0
  39. package/lib/prospective-holdout.js.map +1 -0
  40. package/lib/repair-admission.d.ts +11 -0
  41. package/lib/repair-admission.d.ts.map +1 -0
  42. package/lib/repair-admission.js +25 -0
  43. package/lib/repair-admission.js.map +1 -0
  44. package/lib/repair-agent.d.ts +44 -0
  45. package/lib/repair-agent.d.ts.map +1 -0
  46. package/lib/repair-agent.js +241 -0
  47. package/lib/repair-agent.js.map +1 -0
  48. package/lib/repair-feedback.d.ts +70 -0
  49. package/lib/repair-feedback.d.ts.map +1 -0
  50. package/lib/repair-feedback.js +79 -0
  51. package/lib/repair-feedback.js.map +1 -0
  52. package/lib/repair-profile.d.ts +27 -0
  53. package/lib/repair-profile.d.ts.map +1 -0
  54. package/lib/repair-profile.js +51 -0
  55. package/lib/repair-profile.js.map +1 -0
  56. package/lib/repair-runtime.d.ts +35 -0
  57. package/lib/repair-runtime.d.ts.map +1 -0
  58. package/lib/repair-runtime.js +181 -0
  59. package/lib/repair-runtime.js.map +1 -0
  60. package/lib/replay.d.ts +38 -0
  61. package/lib/replay.d.ts.map +1 -0
  62. package/lib/replay.js +240 -0
  63. package/lib/replay.js.map +1 -0
  64. package/lib/sealed-holdout.d.ts +20 -0
  65. package/lib/sealed-holdout.d.ts.map +1 -0
  66. package/lib/sealed-holdout.js +12 -0
  67. package/lib/sealed-holdout.js.map +1 -0
  68. package/lib/service.d.ts +968 -0
  69. package/lib/service.d.ts.map +1 -0
  70. package/lib/service.js +1929 -0
  71. package/lib/service.js.map +1 -0
  72. package/lib/store.d.ts +366 -0
  73. package/lib/store.d.ts.map +1 -0
  74. package/lib/store.js +1517 -0
  75. package/lib/store.js.map +1 -0
  76. package/lib/version.d.ts +2 -0
  77. package/lib/version.d.ts.map +1 -0
  78. package/lib/version.js +2 -0
  79. package/lib/version.js.map +1 -0
  80. package/lib/watch-proof.d.ts +30 -0
  81. package/lib/watch-proof.d.ts.map +1 -0
  82. package/lib/watch-proof.js +209 -0
  83. package/lib/watch-proof.js.map +1 -0
  84. package/package.json +141 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 dsh-enhanced contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,211 @@
1
+ # Assistant Skills
2
+
3
+ Save a successfully verified Goal's tool workflow and reuse it in a new Goal. The optional bundle publishes private, versioned skills through the native DSH skill catalog and executes fixed steps through the current Agent's native ToolRuntime.
4
+
5
+ ```sh
6
+ dsh plugin --profile web add @dsh-enhanced/assistant-skills
7
+ ```
8
+
9
+ Install the Goals, Delivery and Policy bundles and native Skills/Tools services in the same Host. Goals must be `@dsh-enhanced/assistant-goals >=0.1.25 <0.2.0` and have native execution and independent whole-goal verification configured; the minimum supplies the Host-only failure-evidence and exact-run-proof APIs used by failure candidates and causal canary watches. This bundle never enables those services or creates acceptance profiles automatically.
10
+
11
+ Configuration:
12
+
13
+ ```yaml
14
+ - id: dsh-enhanced-assistant-skills
15
+ config:
16
+ databasePath: /private/state/assistant-skills.sqlite
17
+ allowedTools: [read, write, edit]
18
+ maxDurationMs: 60000
19
+ candidateTtlMs: 86400000
20
+ ```
21
+
22
+ Policy must explicitly authorize the desired `inspect`, `save`, `run`, `retire` actions on `{ kind: evolution, id: verified-workflows }` for the exact owner, workspace and preset. Save/run/retire consume configured Policy authorization budgets with stable idempotency keys; catalog reads only preview current authorization. Native tool execution still requires its own current authorization and approval. Saving and retiring also require the current authenticated human request.
23
+
24
+ After a Goal completes with a current independently achieved outcome, ask the assistant to save it. `skill_save` takes `goal_id`, a kebab-case `name`, `description`, `expected_version` (0 for the first version), and optional `bindings_json`. Each binding is `{ "name": "output_path", "stepId": "<source tool call ID>", "path": "/file_path" }`. The path selects an actual scalar argument and derives its type/default; it does not evaluate code. The saved trace contains at most 32 successful calls and 256 KiB of arguments. Failed, unfinished, recursive skill, goal-control and dynamic orchestration traces are rejected. Catalog descriptions and saved inputs remain task data, not instructions granting authority.
25
+
26
+ Load the saved skill using the native `skill` tool. Create a new Goal with independently configured acceptance, then call `skill_run` with `goal_id`, `name`, `version`, `inputs_json`, and a stable `invocation_id`. If the exact current owner Goal is active but lacks an admitted native round, it returns `awaiting-native-round`, performs no step or durable invocation, and ends the owner turn; the Host native driver starts the round and that round repeats the same invocation ID. Missing declared inputs retain their saved defaults. Extra inputs or type mismatches are rejected. Steps execute in recorded order with current owner/Goal/Policy checks before and after each dispatch. This is a tool composition in the existing native Goal, not another agent loop, scheduler, or queued job.
27
+
28
+ `skill_status` lists active versions, their typed inputs and exact source acceptance, or reads a `run_id`. An invocation's `succeeded` state only means its tool steps succeeded: the new Goal still needs its own independent acceptance. Version updates use CAS and retain the prior version as provenance. Only the latest active version can run; retiring it does not reactivate an older version. Candidate trials and owner-requested activation/rollback are described below. Automatic promotion and rollback are limited to qualified finite canary deployments with an operator-pinned task family; public standalone watches are observation-only.
29
+
30
+ Only one invocation may be running for a given owner/session/Goal, including concurrent native ToolRuntime callers. A budget denial preserves a failed invocation audit and dispatches no business tool. Repeated invocation IDs never repeat effects, including after Host restart. A different goal, version or input under the same invocation ID is rejected. An `unknown` or running invocation also fences a different invocation ID for that same skill or candidate trial in the same Goal, so unresolved external effects cannot be retried by changing the key; use a distinct new Goal only after explicit repair. Interrupted runs recover as `unknown`, with completed step receipts retained; they need explicit inspection and repair. Failure stops remaining steps and returns an actual failed native tool result after preserving the invocation record. No arbitrary effects are automatically reversed: compensation is stop-and-report, not a claim that writes or external actions can be undone.
31
+
32
+ Newly captured standard `write`/`edit` workflows always declare `fileObservations`. A declaration grants no read permission: execution refuses it unless the current Host allowlist permits `read`. Each declaration performs a native read of the instantiated target immediately before its mutation, through the same owner, Goal, tool permissions and budget. Only a structured `FS_NOT_FOUND` may satisfy a write's absent-file observation; edit requires a successful read. Denial, cancellation, other read errors and a concurrent file-version change stop execution. These reads have distinct audit/checkpoint entries and count toward the 32-call limit, argument limit and isolated comparison budget. They do not disable the Host filesystem guard. Existing definitions without declarations keep their original semantics and digest; recapture, trial and authorize a new version to adopt the new preconditions. Failed invocations remain non-replayable.
33
+
34
+ A successful `skill_run` inside an independently accepted source Goal may be captured as fixed, bound steps only after the Host verifies the exact stored invocation, owner/session/Goal/native execution, inputs, active definition version and complete successful checkpoints. The original source call and bounded `runExpansions` proof stay in provenance; reusable steps contain the resolved ordinary tools, not a recursive `skill_run`. Missing, failed, unknown, mismatched or superseded invocations cannot be expanded. The new candidate still needs its own trial or prospective qualification before activation.
35
+
36
+ Distinct successful invocations of the same skill retain their own bound inputs and ordered steps when captured together. Repeated responses for the same durable invocation are rejected as a capture source; they do not prove a second execution and must not create duplicate replay steps.
37
+
38
+ Successful, schema-valid `todo_write` planning updates and parameterless `skill_status` catalog reads remain in source provenance and are omitted from reusable action steps. They cannot be parameter binding targets. Failed source probes remain provenance only; they do not grant an absent-file exception.
39
+
40
+ ## Owner-preauthorized capture
41
+
42
+ During the current authenticated owner turn that creates an active Goal, `skill_capture(owner_route_id, goal_id, name, description, parent_version, expires_at, start_native_rounds?)` can register one finite capture for that exact owner Session and native Goal. `owner_route_id` is an explicitly configured public owner-route identifier. It records the owner-route receipt, immutable Goal definition digest, native Goal identity, and current parent version/digest. The explicit expiry is at most seven days. With the optional `start_native_rounds: true`, a successful registration ends the owner turn and hands the Goal to the Host native driver for execution and later extraction. On registration failure, or when omitted or `false`, the turn stays open so the owner can compose other authorized schedule or wait work. The capture does not create an AgentLoop or execute Goal work. Registration grants no replay, comparison, trial, activation, or broader tool authority.
43
+
44
+ After a Verifier receipt nudge, startup, or a normal skill reconciliation, the service asks the Goals Host-only `inspectOwnerVerifiedWorkflowSource` bridge to reread the exact source. Only a cold, quiescent, independently `achieved` source with the same route, owner scope, Goal definition, native identity and parent can create one durable pending candidate from its actual successful trace. The normal definition allowlist still rejects unsupported traces. A Host may explicitly allowlist parameterless native `get_goal` as a read-only trace step; `create_goal`, `update_goal`, other `goal_*` controls and recursive skill/workflow tools remain rejected; the exact successful source-Goal `goal_checkpoint` exception below is provenance only and is never replayed. Goals may attach its trusted `failedObservations` of allowed read-only probes as immutable provenance. They are not definition steps and are never replayed. Any unconfirmed call, failed or unknown non-probe call, or failed write still prevents Goals from producing a capture source. The capture and candidate are committed together; replay and restart do not make another candidate. `skill_captures` exposes `pending`, `captured`, `revoked`, `expired`, `unsupported`, or `unknown` durable state.
45
+
46
+ For an iterative Goal, the owner bridge may provide contiguous native-round `segments`. The final whole-goal receipt accepts the resulting work; earlier segments establish successful, quiescent execution, not individual goal achievement. Skills validates the final segment against the v1 top-level source and builds its execution steps from all segments in order, preserving an initial write followed by a later repair. Failed observations remain provenance only. The 32-call and 256-KiB argument bounds apply to the entire sequence. A missing round, changed definition, or failed/unknown effect prevents automatic extraction; reuse still requires a fresh Goal and new independent acceptance.
47
+
48
+ A successful `goal_checkpoint` with the exact source Goal ID and strictly validated planning parameters remains in the immutable source trace but is excluded from executable steps. These are historical planning notes, not read-only observations, acceptance or future authority. They cannot receive input bindings, and their IDs and bytes still count toward the full trace bounds. Planning-only traces, failed checkpoints, foreign Goal IDs and other Goal controls remain rejected. Dependencies between executable steps skip these non-replayed notes.
49
+
50
+ Background capture requires a separate explicit Policy `capture` rule for subject `{ kind: background, id: dsh-enhanced-assistant-skills, workspace, principal }` and the exact evolution resource, plus a stable capture authorization budget key. Route, Policy, parent, and definition are checked before and after the Goals Host read. Revocation, expiry, parent/definition drift, and unsupported traces stop the record. The typed Goals bridge reports `pending` or `unavailable` while a source may still become complete; `unknown` and `rejected` bridge failures are recorded as terminal capture `unknown` and never replayed automatically. Captured candidates remain private and pending until the existing owner-requested trial/activation flow runs.
51
+
52
+ ## Failure-driven candidates
53
+
54
+ `skill_failure_candidate` accepts either the legacy exact `trigger_goal_id` / `trigger_session_id` pair for one failure, or `failure_locators` plus `minimum_occurrences` for a bounded repeated-failure window. The latter contains only 1–32 `{ session_id, goal_id }` locators; callers cannot submit outcomes, receipts, trace digests, failure categories or provenance. Goals rereads each locator through its current Host-only capability and aggregates only distinct, exact, independently accepted `not-achieved` runs. Every failure and the repair must retain the same owner route, scope, immutable Goal definition and outcome profile, while using independent Goal, Session, native Goal, execution run, contract and receipt identities. The repair must be one exact independently `achieved`, complete Goal accepted later than every failure. A minimum of two produces `repeated-not-achieved`; one retains `objective-not-achieved`. Invalid, expired, changed or mixed evidence fails closed. The public candidate keeps the existing v1 failure metadata fields and adds `count` / `digest` aliases for repeated windows; raw Goal, Session, run, contract, receipt and trace identities remain private.
55
+
56
+ The repair's successful trace supplies the pending candidate definition; the failures supply its Host-derived trigger and provenance. The model-visible candidate projection exposes only the failure category, count and integrity digest, never the locator list, owner route, Session/native Goal/run identities, receipts or raw proof. Candidate creation still requires current owner, route, Policy, parent and definition checks. It does not activate the candidate, authorize a comparison or prove that the repair is better than its parent.
57
+
58
+ ## Finite outcome watches
59
+
60
+ An owner may explicitly create `skill_watch` for one current version and its immediate-parent fallback metadata. It requires the current authenticated owner request, Policy `watch` permission, a configured `owner_route_id`, an absolute `expires_at`, `max_runs`, and `failure_threshold`. The lifetime is at most seven days, `max_runs` is 1–100, and `failure_threshold` is 1–`max_runs`. Policy must also explicitly allow background `watch` on `{ kind: evolution, id: verified-workflows }` for subject `{ kind: background, id: dsh-enhanced-assistant-skills, workspace, principal }`, with background initiator. The route is revalidated before every durable evidence read. A revoked or changed route, expiry, retirement, or any version/digest change stops the watch; it does not follow a newer version.
61
+
62
+ The watch records a durable run watermark at creation and observes only later `skill_run` calls that actually succeed and whose native Goal execution-run binding was durably recorded. A Verifier receipt is merely a nudge: the service rereads Goals' owner-scoped snapshot, matches the exact execution run and immutable Goal definition, then accepts only a fresh, unexpired independent whole-goal `achieved` or `not-achieved` receipt. Each invocation and receipt digest is counted once, up to the first `max_runs` attached runs; it stops as exhausted when all of those runs have qualifying outcomes without reaching the failure threshold. Repeated receipts, old receipts, wrong Goals/runs, old skill versions and unknown evidence do not count. Reconciliation also runs after restart; it creates no scheduler or polling loop.
63
+
64
+ Public `skill_watch` has no operator-pinned task family, so it is strictly observation-only: neither `achieved` nor `not-achieved` changes the active version, and `failure_threshold` is retained only as bounded watch metadata. `skill_watches` exposes the durable state and observations. Only the qualified canary flow below creates a watch with an exact operator-pinned task family and a matching deployment record; only that pair may automatically promote or append the immediate-parent fallback. A Goal from another task family cannot authorize either mutation.
65
+
66
+ Qualified canary deployments additionally consume Evaluation's Host-only current `goal-outcome/<assessmentId>` projection. Skills subscribes to Evaluation lifecycle-scoped task-change nudges, performs a cold reread when the provider appears or is replaced, and unsubscribes with the injected provider fiber. A notification carries no authority: every reconciliation rereads the exact canonical scope and assessment. Provider absence leaves the durable deployment intact but cannot admit or dispatch new deployed work.
67
+
68
+ The first accepted canary observation freezes an immutable binding of run ID, assessment subject, Verifier receipt digest and validity times, execution-trace digest, and operator-pinned task-family digest. Later Evaluation revisions may replace only the canonical status for that exact binding. A strictly newer `not-achieved` revision replaces an earlier achieved observation; an exact `retract` removes it and records durable invalidation. Same-version duplicates are idempotent only when digest and disposition are identical, lower versions cannot restore evidence, and subject/scope/owner/run/profile drift is rejected. For a qualified deployment, correction or retract reaches the existing exact-version rollback transaction: it appends the pre-bound immediate parent only if the watched version, definition and fallback digests are still current, and never overwrites a later version. Restart preserves the latest canonical revision and cannot resurrect a withdrawn success.
69
+
70
+ Evaluation's `withTrustedCanonicalTaskWriterFence` holds the exact scope watermark plus subject/ref/version/digest/disposition while Skills atomically replaces or invalidates the observation, reconciles deployment state and, when required, writes the rollback version. Promotion fences every canonical observation counted toward quorum, so an unrelated stale success cannot authorize the transition. Before a deployed invocation is claimed, again after its quota slot is reserved, and before every native tool dispatch, Skills rereads and briefly fences every recorded canonical revision; an Evaluation change also aborts active deployed executions. Missing/replaced Evaluation, changed evidence or a failed fence closes admission before claim; a failure after reservation is recorded as `unknown` and cannot replay. The synchronous fence cannot remain held across an asynchronous external tool, so a non-cooperative tool may still complete after a later correction; its effects are not undone and the run remains conservatively unknown. New qualified watches use `canonical-goal-outcome/v2`; legacy or malformed active qualified deployments without exact canonical evidence are blocked on reopen without changing the active definition. This revision monitor is limited to qualified canary deployments. Standalone watches deliberately retain their legacy immutable-receipt, observation-only behavior, and no other deployment cohort is claimed.
71
+
72
+ ## Candidate trials, activation and rollback
73
+
74
+ To review a potential replacement while keeping the current skill active:
75
+
76
+ 1. After an independently achieved source Goal, call `skill_candidate` with `goal_id`, `name`, `description`, `bindings_json`, the current `parent_version` (or 0 for a new name), `reason` and `trigger`. The current human owner request is required. `skill_candidates` reads the pending definition and Host-derived structural difference: added/removed tools, changed step digests and input changes. These differences do not measure quality or infer an expanded permission grant.
77
+ 2. In a fresh Goal with its own acceptance profile, call `skill_trial` with `candidate_id`, `goal_id`, `inputs_json` and a stable `invocation_id`. Before an admitted native round it returns the same no-work `awaiting-native-round` handoff and the next native round repeats that ID. Trial steps use the ordinary native tools and may have real effects once admitted. They retain the same duration limit, owner/Goal checks, current tool approval and budget handling as `skill_run`. Pending candidates are absent from the native catalog.
78
+ 3. After that exact trial independently achieves its Goal, the owner can request `skill_activate` with `candidate_id` and `trial_run_id`. The accepted source turn must contain exactly one successful `skill_trial`, with matching candidate, Goal, invocation and inputs, as its only business execution. It may also contain only successful, parameter-validated metadata reads: `get_goal({})`, `skill_candidates({})` or its exact candidate ID, `skill_status({})` or its exact trial run ID, and `goal_context({})` or the exact Goal with omitted or `false` focus. A later repair call, another trial, business tool, control mutation, unknown field, failed/unknown call, or unrelated accepted run cannot authorize activation. Reading an older accepted Goal is allowed only in its original owner Session with an unexpired receipt. The current parent must still match.
79
+ 4. `skill_rollback` takes `name`, `expected_version` and `target_version`, where the target is the current version's immediate parent. It copies the parent into a new immutable version: activating v2 over v1 and rolling back produces v3 with `restoredFromVersion: 1`. Old versions and runs remain recorded. Repeating the same rollback does not append another version. `skill_reject` discards a pending candidate without changing the active skill.
80
+
81
+ To activate with an observation watch in the same commit, use `skill_activate_watched(candidate_id, trial_run_id, owner_route_id, expires_at, max_runs, failure_threshold)`. It requires an existing parent, the same exact independently accepted trial and current owner request, `activate` and `watch` permissions, and background `watch` authority for the current owner route. The new immutable version, candidate activation and exact-version watch are written in one SQLite transaction. Invalid or failed watch storage leaves the parent active. A repeated request must retain the exact watch parameters and route binding; it returns the original activation and current watch state without extending the watch. This public flow has no operator-pinned task family, so its observations cannot promote or roll back the active version. The finite watch bounds monitoring, not the lifetime or total executions of the skill.
82
+
83
+ Policy must separately allow `draft`, `trial`, `activate`, `reject` and `rollback` on the same evolution resource. All mutations use stable Policy authorization keys; draft, activate, reject and rollback require the current authenticated human request. Revoked authority, changed parents, failed/unknown trials and expired candidates prevent activation. Candidate lifetime defaults to 24 hours, configurable from one second to seven days; repeating a draft never extends its original expiry. A previously successful activation can be read back idempotently without reactivating it over a later version.
84
+
85
+ This delivers owner-reviewed version changes after a verified trial. Owner-preauthorized capture can form one pending candidate from an exact independently achieved successful trace, and the failure entrypoint above can form one from one or more exact independently accepted failures followed by a later exact achieved repair. Partial, unknown, mixed-task and unverified broader traces remain unsupported. Prospective comparison and finite automatic canary admission use the separate entrypoint below; finite rollback watches and trial success alone do not establish causal improvement.
86
+
87
+ ## Actual parent/candidate comparisons
88
+
89
+ `skill_compare(candidate_id, profile_id, invocation_id)` executes the parent and pending candidate on the same operator-configured inputs and limits. Each arm uses native read/write/edit tools in a private temporary workspace and a separate isolated artifact runner; the Host compares actual behavior against its expected output. Results persist and can be read with `skill_comparison_status` after restart. Failed/unknown attempts are not automatically repeated, and current owner/Policy/parent/expiry are checked during execution.
90
+
91
+ This optional capability needs the Evaluation and Isolation packages plus an explicit finite comparison profile and Policy `compare` permission. See [comparison configuration and limits](../../docs/skill-comparison-profiles.md). A Host may also register an opaque, Host-attested comparison plan; its binding digest is recorded, but this bundle ships no production plan provider and the attestation does not prove OS-level sealing, historical independence, or model inaccessibility. Reports separate evaluation gains from critical regressions; a complete run with zero gain is not an improvement. They never grant promotion permission or establish independent holdout evidence. The candidate stays pending until a separately authorized lifecycle action changes it.
92
+
93
+ ## Independent operator judging process
94
+
95
+ The installed `dsh-skill-holdout --config /private/config.json` CLI holds an operator-selected dataset and Ed25519 key in a separate evaluation process. It issues one input at a time to a trusted executor, independently checks actual output, and signs a report bound to the exact scope, arms, dataset, limits and budget identity. State is committed before responses; concurrent controllers are fenced and a recovered unconfirmed cell is never reissued. Deploy the authority outside candidate workers and pin its public key independently. The CLI is not a model tool and does not execute candidate code, supply an in-process sealed provider, prove historical data independence, or authorize promotion. See [configuration, pipe protocol and deployment boundaries](../../docs/skill-holdout-authority.md).
96
+
97
+ Configure a finite `externalHoldouts` profile with the exact owner scope, candidate execution limits, fixed authority command, public-key and dataset pins. `dsh-skill-holdout --inspect-config` exports those public pins without consuming a qualification. With current owner and Policy `compare` authorization, `skill_qualify(candidate_id, profile_id, invocation_id)` runs the external judge through the installed Skills service and records its signed result in the existing comparison journal. Each profile permits one qualification across sessions. The same invocation never restarts completed or unknown work, including after Host restart. The private command/configuration, setup files and raw case inputs/outputs are absent from tool responses; public signed receipts contain identity digests and the verification public key. Comparison still grants no automatic activation.
98
+
99
+ `skill_comparison_status` labels configured local profiles with `kind: "local"` and `executionTool: "skill_compare"`, and external profiles with `kind: "external"` and `executionTool: "skill_qualify"`. A prospective external profile exposes `canaryExecutionTool: "skill_canary"` only when its configured public profile pins both a `generatorDigest` and the exact `canaryAdmission`; that field identifies the available entrypoint, never authorization. Profile IDs are opaque operator-selected IDs: when the owner did not provide the exact configured ID, query `skill_comparison_status` and use its exact `id`; never derive one from a dataset, generator, task or version label. `skill_canary` starts its own prospective comparison and deploys only after all qualification and authorization gates pass; it does not make a prior qualification an additional permitted attempt. Status remains owner-scoped and omits authority keys, private inputs, commands and state paths. Candidate and canary mutation responses use the same explicit public projection: source traces, owner/session/native Goal identities, route receipts, individual run IDs and raw failure evidence remain Host-private, while stable public digests, counts, lifecycle state and structural differences remain available for review and subsequent calls.
100
+
101
+ ### Finite automatic canary
102
+
103
+ An operator can instead configure a supported `prospective.generator` in the private authority and pin the inspected `generatorDigest` in the Host profile, omitting `datasetDigest`. The authority freezes the candidate/baseline/budget before generating private random cases. `order-summary/v1` and `order-summary/v2` are versions of one order-summary family; v2 uses integer `amountCents`, including negative values, cancelled orders and empty input, while v1 retains its nonnegative `cents` contract and digest. `template-render/v1` is the second family. `dependency-topological-order/v1` is the third: it accepts only edge lines containing exactly two labels matching `[a-z][a-z0-9]{1,31}`, ignores blank/malformed lines, deduplicates edges, and emits the lexicographically smallest topological order one node per line or `CYCLE\n`. Its private replay/evaluation/regression cases cover a DAG, a dynamically introduced lexical tie and a cycle. Each profile has a distinct inspected pin; changing profiles cannot reset a consumed authority. These are three deterministic engineering task families, not arbitrary task domains, historical training independence or real-model gain.
104
+
105
+ With a current owner request, `canary`/`compare`/`watch` Policy permissions and current background `promote`/`watch`/`rollback` authority, `skill_canary(candidate_id, profile_id, invocation_id, owner_route_id, expires_at, max_runs, canary_runs)` compares and admits a candidate only when its signed prospective receipt passes candidate checks, positive evaluation gain and critical regressions. Exact version activation, the execution quota and rollback watch commit atomically. Standalone qualification receipts do not grant permission.
106
+
107
+ Use ordinary `skill_run` in fresh native Goals. Initially only `canary_runs` executions are allowed; fresh distinct independently achieved outcomes promote the version within the original `max_runs` total and expiry. Promotion and every later deployed dispatch require those accepted observations to remain the current fenced Evaluation revisions. Limits are 1–100 total runs and at most seven days, no later than the qualification profile's expiry. Failed or unknown runs retain their charged slot and block further execution, including after restart. A later canonical `not-achieved` correction or withdrawal of a previously accepted Goal outcome triggers the same exact-version parent rollback; revoked authority, unavailable canonical evidence or expiry prevents further use. `skill_deployment_status` exposes durable state and charged runs. Identical activation retries cannot renew or resurrect a deployment.
108
+
109
+ See the [operator configuration and complete authorization flow](../../docs/skill-holdout-authority.md#prospective-qualification-and-finite-canary). Engineering tests with synthetic programs verify admission and lifecycle behavior; they do not establish real user-task or model intelligence gains. The candidate runs in the existing isolated artifact runner; the private authority's files, pipe and keys remain outside its authority. No additional network, credential or install-script authority is granted by this tool.
110
+
111
+ Fixed replay comparison now retains validated workspace-contained glob/grep and parameterless get_goal as explicitly omitted observations. Their original steps still count against the declared tool-call and byte limits; reports also state actual executed tool calls. They do not run, produce fabricated results or change the immutable source. Other controls and unsupported tools remain rejected by the offline comparator.
112
+
113
+ ## Authority and privacy
114
+
115
+ - Filesystem: creates a private SQLite database (0600), WAL/SHM and new parent directory (0700). The store contains owner-scoped historical tool arguments, input defaults, acceptance references and invocation receipts. These may contain private task content; do not put the database in a shared or public directory. Symlink/nonregular database files are rejected.
116
+ - Comparison authority: finite operator-configured offline Docker verification, private benchmark journals and temporary file workspaces; native read/write/edit only. The calling Agent receives no general verifier runner handle or expected-answer payload.
117
+ - Filesystem/network/subprocess effects during reuse: only through saved, Host-allowlisted native tools with their current approvals, Policy, cancellation and Goal budget. The optional external qualification configuration additionally authorizes a fixed Host subprocess and isolated candidate verification; its executable, arguments and container mounts are trusted operator choices, never model arguments.
118
+ - Credential/browser authority: the separately invoked operator CLI reads only its configured private Ed25519 key, dataset and configuration files, and writes its private qualification SQLite state. It uses stdin/stdout for a trusted controller and has no network listener or browser. The ordinary Skills service does not load these files or gain signing authority. Native tools retain their own requirements.
119
+ - Install scripts: no runtime install/postinstall scripts. Build/prepack scripts compile the independently publishable bundle.
120
+ - Historical acceptance is checked at capture. It is provenance for the saved workflow, not future task acceptance or a permanent grant. Owner lineage/workspace/preset changes isolate saved data and stop subsequent dispatches.
121
+
122
+ Validation uses package tests for native tool dispatch, typed inputs, owner isolation, current permission checks, retirement, persistence and no replay, plus `pnpm test:web-owner:real-skill` (reuse) and `DSH_WEB_REAL_SKILL_CANDIDATE=1 pnpm test:web-owner:real-skill` (candidate lifecycle) for the explicitly configured real-route Web scenario. See repository evidence for runs actually completed.
123
+
124
+ The capture/canary Web tests can use an already logged-in TraeX account in a fresh temporary profile: `DSH_WEB_REAL_PROVIDER=traex-agent DSH_WEB_REAL_MODEL=gpt-5.6-terra pnpm test:web-owner:real-canary`. Select a model available in that account's current catalog; omitting `DSH_WEB_REAL_MODEL` uses TraeX's `default`. This installs the TraeX adapter only in the test profile, binds it to the test workspace, and never falls back to the Codex subscription route. Canary tests also require `DSH_HOLDOUT_TEST_IMAGE` with the pinned Node image and an available Chromium executable. Call/deadline limits remain enforced; TraeX usage is not treated as a verified token or monetary cap.
125
+
126
+ ### Owner-authorized repair continuation (experimental)
127
+
128
+ An operator may configure `repairProfiles` to expose `skill_repair_arm`,
129
+ `skill_repair_status`, and `skill_repair_revoke`. The owner selects a profile and
130
+ an exact source Goal, route, invocation id and expiry. One authorization permits
131
+ a finite sequence of independent repair Goals, each with its own prospective
132
+ comparison and canary. `maxIterations` defaults to one and is limited to four;
133
+ `followupProfileIds` explicitly names every subsequent profile in order. Arming
134
+ freezes the full sequence and its digests. The sequence cannot renew its expiry,
135
+ expand tool/model authority, or reset cumulative model/tool call budgets.
136
+
137
+ A repair profile contains `id`, exact `scope` (principal id, record id/version,
138
+ workspace and preset), `skillName`, `taskFamilyId`, `description`, optional typed
139
+ capture `bindings`, `externalHoldoutProfileId`, `provider`, `model`,
140
+ `allowedTools`, `maxGoalRounds`, `maxModelCalls`, `maxToolCalls`,
141
+ `maxOutputTokens`, `maxDurationMs`, `canaryRuns`, and `maxCanaryRuns`, plus optional
142
+ `maxIterations` and `followupProfileIds`. Each followup uses the same owner, skill
143
+ and model route with no broader tool, output, round or duration limits.
144
+ The selected external holdout must use a prospective `generatorDigest` and
145
+ `canaryAdmissionTemplate`:
146
+
147
+ ```json
148
+ {
149
+ "protocol": "assistant-skills/canary-admission-template/v1",
150
+ "skillName": "saved-workflow",
151
+ "taskFamily": {
152
+ "goalDefinitionDigest": "<exact configured Goal definition digest>",
153
+ "outcomeProfile": { "id": "task-outcome", "version": 1, "digest": "<profile digest>" }
154
+ }
155
+ }
156
+ ```
157
+
158
+ A template and a static `canaryAdmission` are mutually exclusive. The Host fills
159
+ in the actual parent and newly captured candidate digests after independent
160
+ repair acceptance. Model tools cannot supply evaluator cases, rewrite this
161
+ configuration, create another Goal, or promote themselves. The ordinary public
162
+ capture/canary tools retain their current-human-request requirements.
163
+
164
+ Install the native Goal service and goal-round driver before creating repair
165
+ Agents. Configure Goals' preauthorized round limit, independent native-round and
166
+ whole-goal acceptance, and a compatible registered budget meter. The selected
167
+ preset and model must support the required native tool protocol. Background
168
+ Policy must permit both identities: the configured preset's background Agent
169
+ needs Goal `create/observe/execute`, its allowed file tools, and Skills
170
+ `draft/compare/canary/watch`; the `dsh-enhanced-assistant-skills` background
171
+ service needs `draft/compare/canary/promote/watch/rollback`. Scope both to the
172
+ authorized principal and workspace. `notify: true` additionally requires the
173
+ service's background message `send` permission. Allowing only the service does
174
+ not authorize the Agent's candidate capture. `repairProfiles` is empty by default; manual skills do not
175
+ acquire these runtime dependencies or start repair Agents.
176
+
177
+ When the source Goal has stopped and has an exact independent `not-achieved`
178
+ receipt, the Host creates a separate root Session in the authorized workspace.
179
+ The native driver owns model rounds. The model receives the original objective
180
+ and chooses its repair; the Host supplies no repaired program. It captures only
181
+ an independently accepted repair trace, then uses the existing external holdout
182
+ and canary gates. Each boundary rechecks the durable intent, profile, owner
183
+ route, source definition, parent version, expiry and background policy. A
184
+ process-local capability links Goals to the current Skills instance; it is not
185
+ isolation from arbitrary malicious plugins sharing the same Host process.
186
+
187
+ A successor starts only after the prior version is promoted and a distinct
188
+ new task using that version has independently failed under the next configured
189
+ acceptance profile. The source run must have started strictly after the immutable
190
+ promotion time. Old promoted records without that evidence cannot authorize a
191
+ successor. Each iteration uses a fresh Session; the previous Agent closes before
192
+ continuation advances. Profile changes, revoked authority and expiry prevent
193
+ new work.
194
+
195
+ `skill_repair_arm` accepts `notify: true` only from the owner route Session and
196
+ with current background send Policy. It freezes that Session and route receipt
197
+ for iteration and final-result notices through Delivery’s durable Outbox. Stable
198
+ keys deduplicate notices across runtime ticks and restarts.
199
+
200
+ Armed waits and deployed watches survive restart. A restart during dispatch, or
201
+ before the native repair Agent can be safely reacquired, surfaces `unknown`
202
+ without creating a second repair. Automatic resumption of an interrupted repair
203
+ Agent is not implemented. Status includes the exact repair Session/Goal and
204
+ candidate/deployment references. The `test:web-owner:real-repair` journey checks
205
+ two successive improvements, future-task promotion, original-session feedback
206
+ and absence of replay after completion and restart. `skill_repair_revoke` stops the remaining continuation; completed
207
+ filesystem effects or a deployed version require their existing explicit
208
+ rollback controls. Repair Agents use the configured workspace, model route and
209
+ tool authority, and may write files there; they are not an OS sandbox. Calls and
210
+ deadlines are finite; token or monetary accounting still depends on the route's
211
+ registered meter. No installation script or credential authority is added.
@@ -0,0 +1,3 @@
1
+ - insert:
2
+ - id: dsh-enhanced-assistant-skills
3
+ name: '@dsh-enhanced/assistant-skills'
@@ -0,0 +1,18 @@
1
+ import type { GoalScope } from '@dsh-enhanced/assistant-goals';
2
+ import type { FailureCaptureProvenance, HostFailureEvidenceSummary, VerifiedWorkflowSource } from './definition.js';
3
+ import { type SkillDefinition, type SkillRunExpansion } from './definition.js';
4
+ import type { SkillStore, StoredSkillDefinition } from './store.js';
5
+ /**
6
+ * Bind current-Goals-capability not-achieved evidence to a later, independently
7
+ * achieved repair. This freezes comparison metadata only; it neither stages
8
+ * nor activates a candidate and grants no authority. The public evidence
9
+ * digest is an integrity link, not producer authentication.
10
+ */
11
+ export declare function captureFailureCandidateProvenance(trigger: HostFailureEvidenceSummary, repair: VerifiedWorkflowSource, scope: GoalScope, parent: StoredSkillDefinition, candidate: SkillDefinition): Readonly<FailureCaptureProvenance>;
12
+ /**
13
+ * Turn a verified source's outer `skill_run` calls into immutable native-step
14
+ * proof. The source still carries the raw outer call; definition construction
15
+ * consumes this proof to substitute only the exact already-verified run.
16
+ */
17
+ export declare function captureRunExpansions(source: VerifiedWorkflowSource, scope: GoalScope, store: SkillStore): readonly SkillRunExpansion[];
18
+ //# sourceMappingURL=capture-expansion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capture-expansion.d.ts","sourceRoot":"","sources":["../src/capture-expansion.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAA;AAC9D,OAAO,KAAK,EAAE,wBAAwB,EAAE,0BAA0B,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AACnH,OAAO,EAA2G,KAAK,eAAe,EAAE,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AACvL,OAAO,KAAK,EAA0B,UAAU,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AA8E3F;;;;;GAKG;AACH,wBAAgB,iCAAiC,CAC/C,OAAO,EAAE,0BAA0B,EACnC,MAAM,EAAE,sBAAsB,EAC9B,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,qBAAqB,EAC7B,SAAS,EAAE,eAAe,GACzB,QAAQ,CAAC,wBAAwB,CAAC,CAsCpC;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,sBAAsB,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,GAAG,SAAS,iBAAiB,EAAE,CAiCtI"}
@@ -0,0 +1,187 @@
1
+ import { acceptanceDigest } from '@dsh-enhanced/task-acceptance-contract';
2
+ import { fileObservationSteps, instantiate, validateFailureCaptureProvenance, validateHostFailureEvidenceSummary } from './definition.js';
3
+ const resultDetail = /^result:[a-f0-9]{64}$/u;
4
+ const maximumInputsBytes = 256 * 1024;
5
+ function fail(message) { throw new Error(`assistant-skills: ${message}`); }
6
+ function text(value, maximum = 256) { return typeof value === 'string' && value.length > 0 && value.length <= maximum && !/[\p{Cc}]/u.test(value); }
7
+ function json(value) {
8
+ if (value === null || typeof value === 'string' || typeof value === 'boolean')
9
+ return true;
10
+ if (typeof value === 'number')
11
+ return Number.isFinite(value);
12
+ if (Array.isArray(value)) {
13
+ if (Object.getOwnPropertySymbols(value).length !== 0 || Reflect.ownKeys(value).length !== value.length + 1)
14
+ return false;
15
+ for (let index = 0; index < value.length; index++) {
16
+ const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
17
+ if (descriptor === undefined || !('value' in descriptor) || !json(descriptor.value))
18
+ return false;
19
+ }
20
+ return true;
21
+ }
22
+ if (!value || typeof value !== 'object' || Object.getPrototypeOf(value) !== Object.prototype || Object.getOwnPropertySymbols(value).length !== 0)
23
+ return false;
24
+ const descriptors = Object.getOwnPropertyDescriptors(value);
25
+ return Object.entries(descriptors).every(([key, descriptor]) => key !== '__proto__' && key !== 'prototype' && key !== 'constructor' && descriptor.enumerable && 'value' in descriptor && json(descriptor.value));
26
+ }
27
+ function clone(value) { if (!json(value))
28
+ fail('invalid skill-run expansion value'); return JSON.parse(JSON.stringify(value)); }
29
+ function record(value) { return json(value) && value !== null && typeof value === 'object' && !Array.isArray(value); }
30
+ function sourceSegments(source) {
31
+ if (source.segments === undefined)
32
+ return [{ runId: source.runId, steps: source.steps }];
33
+ if (!Array.isArray(source.segments))
34
+ fail('invalid source expansion segments');
35
+ return source.segments.map(segment => ({ runId: segment.runId, steps: segment.steps }));
36
+ }
37
+ function skillRunInput(value) {
38
+ if (!record(value))
39
+ return undefined;
40
+ const keys = Object.keys(value);
41
+ if (keys.some(key => !['goal_id', 'name', 'version', 'inputs_json', 'invocation_id'].includes(key))
42
+ || !text(value.goal_id, 256) || !text(value.name, 64) || !Number.isSafeInteger(value.version) || value.version < 1 || value.version > 1_000_000_000 || !text(value.invocation_id, 256))
43
+ return undefined;
44
+ const raw = value.inputs_json === undefined ? '{}' : value.inputs_json;
45
+ if (typeof raw !== 'string' || Buffer.byteLength(raw, 'utf8') > maximumInputsBytes)
46
+ return undefined;
47
+ let inputs;
48
+ try {
49
+ inputs = JSON.parse(raw);
50
+ }
51
+ catch {
52
+ return undefined;
53
+ }
54
+ if (!record(inputs))
55
+ return undefined;
56
+ return { goalId: value.goal_id, name: value.name, version: value.version, inputs, invocationId: value.invocation_id };
57
+ }
58
+ function durableRunId(scope, sessionId, invocationId) {
59
+ return `skill-run-${acceptanceDigest([scope, sessionId, invocationId])}`;
60
+ }
61
+ function exactDefinition(store, scope, input) {
62
+ const exact = store.get(scope, input.name, input.version);
63
+ const active = store.get(scope, input.name);
64
+ if (!exact || exact.retired || !active || active.retired || active.version !== input.version || acceptanceDigest(active) !== acceptanceDigest(exact))
65
+ return undefined;
66
+ return exact;
67
+ }
68
+ function expectedRunSteps(definition) {
69
+ const observations = fileObservationSteps(definition);
70
+ const output = [];
71
+ for (const step of definition.steps) {
72
+ for (const observation of observations)
73
+ if (observation.beforeStepId === step.id)
74
+ output.push({ id: observation.id, observation: { allowAbsent: observation.allowAbsent, toolName: step.toolName } });
75
+ output.push({ id: step.id });
76
+ }
77
+ return output;
78
+ }
79
+ function validCheckpoint(run, definition) {
80
+ const expected = expectedRunSteps(definition);
81
+ if (run.steps.length !== expected.length)
82
+ return false;
83
+ return run.steps.every((actual, index) => {
84
+ const wanted = expected[index];
85
+ if (!wanted || actual.id !== wanted.id || actual.state !== 'succeeded')
86
+ return false;
87
+ if (wanted.observation?.allowAbsent === true && wanted.observation.toolName === 'write' && actual.detail === 'absence:FS_NOT_FOUND')
88
+ return true;
89
+ return typeof actual.detail === 'string' && resultDetail.test(actual.detail);
90
+ });
91
+ }
92
+ /**
93
+ * Bind current-Goals-capability not-achieved evidence to a later, independently
94
+ * achieved repair. This freezes comparison metadata only; it neither stages
95
+ * nor activates a candidate and grants no authority. The public evidence
96
+ * digest is an integrity link, not producer authentication.
97
+ */
98
+ export function captureFailureCandidateProvenance(trigger, repair, scope, parent, candidate) {
99
+ const observed = validateHostFailureEvidenceSummary(trigger);
100
+ if (!record(repair) || Object.keys(repair).some(key => !['protocol', 'scope', 'goal', 'runId', 'turn', 'acceptance', 'steps', 'failedObservations', 'segments'].includes(key))
101
+ || repair.protocol !== 'assistant-goals/verified-workflow-source/v1' || acceptanceDigest(repair.scope) !== acceptanceDigest(scope)
102
+ || acceptanceDigest(observed.scope) !== acceptanceDigest(scope) || !record(repair.goal) || !record(repair.goal.definition)
103
+ || !text(repair.goal.id, 256) || !text(repair.goal.sessionId, 256) || !text(repair.goal.nativeGoalId, 256) || !text(repair.runId, 256)
104
+ || !Number.isSafeInteger(repair.goal.definition.version) || repair.goal.definition.version < 1 || !resultDetail.test(`result:${repair.goal.definition.digest}`)
105
+ || !text(repair.goal.definition.objective, 16_384) || repair.goal.definition.digest !== acceptanceDigest({ objective: repair.goal.definition.objective })
106
+ || !record(repair.acceptance) || Object.keys(repair.acceptance).some(key => !['contractId', 'contractDigest', 'receiptDigest', 'verifiedAt', 'validUntil'].includes(key))
107
+ || !text(repair.acceptance.contractId, 256) || !resultDetail.test(`result:${repair.acceptance.contractDigest}`)
108
+ || !resultDetail.test(`result:${repair.acceptance.receiptDigest}`) || !Number.isSafeInteger(repair.acceptance.verifiedAt) || repair.acceptance.verifiedAt < 0
109
+ || !Number.isSafeInteger(repair.acceptance.validUntil) || repair.acceptance.validUntil <= repair.acceptance.verifiedAt
110
+ || !Array.isArray(repair.steps) || repair.steps.length === 0 || repair.steps.length > 32)
111
+ fail('achieved repair source is invalid');
112
+ if (acceptanceDigest(repair.goal) !== acceptanceDigest(observed.repairGoal)
113
+ || repair.goal.definition.digest !== observed.taskFamily.definitionDigest || repair.goal.definition.objective !== observed.taskFamily.objective
114
+ || observed.failures.some(failure => failure.goal.id === repair.goal.id || failure.goal.sessionId === repair.goal.sessionId
115
+ || failure.goal.nativeGoalId === repair.goal.nativeGoalId || failure.runId === repair.runId || failure.acceptance.verifiedAt >= repair.acceptance.verifiedAt)
116
+ || repair.acceptance.verifiedAt > observed.attestedAt || repair.acceptance.validUntil <= observed.attestedAt) {
117
+ fail('achieved repair source is not independent or later');
118
+ }
119
+ if (!parent || parent.protocol !== 'assistant-skills/definition/v1' || parent.retired || !Number.isSafeInteger(parent.version) || parent.version < 1
120
+ || parent.name !== candidate.name || !candidate || candidate.protocol !== 'assistant-skills/definition/v1'
121
+ || acceptanceDigest(candidate.source) !== acceptanceDigest(repair))
122
+ fail('failure candidate binding is invalid');
123
+ const permissions = (definition) => Object.freeze([...new Set(definition.steps.map(step => step.toolName))].sort());
124
+ const parentPermissions = permissions(parent), candidatePermissions = permissions(candidate);
125
+ const before = new Set(parentPermissions), after = new Set(candidatePermissions);
126
+ const output = {
127
+ protocol: 'assistant-skills/failure-capture-provenance/v1',
128
+ trigger: clone(observed),
129
+ repair: { goal: clone(repair.goal), runId: repair.runId, sourceDigest: acceptanceDigest(repair), acceptanceDigest: acceptanceDigest(repair.acceptance) },
130
+ parent: { name: parent.name, version: parent.version, digest: acceptanceDigest(parent) },
131
+ candidate: { name: candidate.name, definitionDigest: acceptanceDigest(candidate) },
132
+ // Diagnostic only: ToolRuntime/Policy must authorize the actual run.
133
+ permissionDelta: { parent: parentPermissions, candidate: candidatePermissions, added: candidatePermissions.filter(tool => !before.has(tool)),
134
+ removed: parentPermissions.filter(tool => !after.has(tool)), expandsAuthority: candidatePermissions.some(tool => !before.has(tool)) },
135
+ rollbackTarget: { name: parent.name, version: parent.version, digest: acceptanceDigest(parent) },
136
+ };
137
+ return validateFailureCaptureProvenance(output);
138
+ }
139
+ /**
140
+ * Turn a verified source's outer `skill_run` calls into immutable native-step
141
+ * proof. The source still carries the raw outer call; definition construction
142
+ * consumes this proof to substitute only the exact already-verified run.
143
+ */
144
+ export function captureRunExpansions(source, scope, store) {
145
+ if (acceptanceDigest(source.scope) !== acceptanceDigest(scope) || !text(source.goal.sessionId, 256) || !text(source.goal.nativeGoalId, 256))
146
+ fail('source expansion scope mismatch');
147
+ const expanded = [];
148
+ const calls = new Set();
149
+ const runs = new Set();
150
+ for (const segment of sourceSegments(source)) {
151
+ if (!text(segment.runId, 256) || !Array.isArray(segment.steps))
152
+ fail('invalid source expansion segment');
153
+ for (const step of segment.steps) {
154
+ if (!step || !text(step.id, 256) || !text(step.toolName, 256) || !json(step.arguments))
155
+ fail('invalid source expansion step');
156
+ if (step.id.includes(':skill:') || step.id.includes(':skill-observation:'))
157
+ fail('nested skill call in source is not reusable');
158
+ if (step.toolName !== 'skill_run')
159
+ continue;
160
+ if (calls.has(step.id))
161
+ fail('duplicate source skill_run call');
162
+ calls.add(step.id);
163
+ const input = skillRunInput(step.arguments);
164
+ if (!input || input.goalId !== source.goal.id)
165
+ fail('source skill_run expansion input is invalid');
166
+ const runId = durableRunId(scope, source.goal.sessionId, input.invocationId);
167
+ if (runs.has(runId))
168
+ fail('duplicate source skill_run execution');
169
+ runs.add(runId);
170
+ const run = store.getRun(scope, runId);
171
+ const definition = exactDefinition(store, scope, input);
172
+ if (!run || !definition || run.state !== 'succeeded' || run.id !== runId || run.goalId !== source.goal.id || run.sessionId !== source.goal.sessionId
173
+ || run.skillName !== input.name || run.version !== input.version || acceptanceDigest(run.inputs) !== acceptanceDigest(input.inputs)
174
+ || run.goalExecutionRunId !== segment.runId || run.goalDefinitionDigest !== source.goal.definition.digest
175
+ || run.nativeGoalId !== source.goal.nativeGoalId)
176
+ fail('source skill_run expansion proof is unavailable');
177
+ const materialized = instantiate(definition, input.inputs);
178
+ if (!validCheckpoint(run, materialized))
179
+ fail('source skill_run expansion checkpoint is invalid');
180
+ expanded.push(Object.freeze({ protocol: 'assistant-skills/run-expansion/v1', callId: step.id, runId,
181
+ runDigest: acceptanceDigest(run), definitionDigest: acceptanceDigest(definition), inputsDigest: acceptanceDigest(input.inputs),
182
+ steps: Object.freeze(materialized.steps.map(item => Object.freeze({ id: item.id, toolName: item.toolName, arguments: clone(item.arguments) }))), }));
183
+ }
184
+ }
185
+ return Object.freeze(expanded);
186
+ }
187
+ //# sourceMappingURL=capture-expansion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capture-expansion.js","sourceRoot":"","sources":["../src/capture-expansion.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ import type { GoalScope } from '@dsh-enhanced/assistant-goals';
2
+ import type { SkillDefinition } from './definition.js';
3
+ export interface SkillComparisonProfile {
4
+ id: string;
5
+ version: number;
6
+ scope: GoalScope;
7
+ stateRoot: string;
8
+ image: string;
9
+ dockerPath: string;
10
+ command: string;
11
+ artifactPath: string;
12
+ expiresAt: number;
13
+ maxComparisons: number;
14
+ repeats: number;
15
+ cellDurationMs: number;
16
+ verificationDurationMs: number;
17
+ maxToolCalls: number;
18
+ maxBytes: number;
19
+ maxOutputBytes: number;
20
+ minimumEvaluationGain: number;
21
+ cases: readonly {
22
+ id: string;
23
+ kind: 'replay' | 'evaluation' | 'regression';
24
+ inputs: Readonly<Record<string, unknown>>;
25
+ files: readonly {
26
+ path: string;
27
+ content: string;
28
+ }[];
29
+ stdin: string;
30
+ expectedStdout: string;
31
+ expectedExitCode: number;
32
+ }[];
33
+ }
34
+ export declare function validateComparisonProfiles(value: unknown): readonly SkillComparisonProfile[];
35
+ /** Host coordinator: fixed native file-tool replay, separate isolated artifact execution, Host-side judge. */
36
+ export declare class SkillComparator {
37
+ #private;
38
+ constructor(profile: SkillComparisonProfile);
39
+ compare(id: string, baseline: SkillDefinition, candidate: SkillDefinition, signal: AbortSignal, authorize: () => void): Promise<{
40
+ protocol: string;
41
+ profileId: string;
42
+ profileDigest: string;
43
+ baselineDigest: string;
44
+ candidateDigest: string;
45
+ report: import("@dsh-enhanced/assistant-evaluation/benchmark").BenchmarkReport;
46
+ cells: {
47
+ id: string;
48
+ artifactDigest: string;
49
+ jobId: string;
50
+ verdict: string;
51
+ quiescent: boolean;
52
+ toolCalls: number;
53
+ executedToolCalls: number;
54
+ omittedObservations: number;
55
+ }[];
56
+ quality: {
57
+ candidateChecksPassed: boolean;
58
+ evaluationGain: number | null;
59
+ evaluationGainObserved: boolean;
60
+ criticalRegressionsPassed: boolean;
61
+ heldoutIndependence: string;
62
+ };
63
+ promotionAuthorized: boolean;
64
+ execution: string;
65
+ modelCalls: number;
66
+ }>;
67
+ close(): Promise<void>;
68
+ }
69
+ //# sourceMappingURL=comparison.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comparison.d.ts","sourceRoot":"","sources":["../src/comparison.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAA;AAG9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAItD,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,SAAS,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,cAAc,EAAE,MAAM,CAAA;IACtB,OAAO,EAAE,MAAM,CAAA;IACf,cAAc,EAAE,MAAM,CAAA;IACtB,sBAAsB,EAAE,MAAM,CAAA;IAC9B,YAAY,EAAE,MAAM,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,cAAc,EAAE,MAAM,CAAA;IACtB,qBAAqB,EAAE,MAAM,CAAA;IAC7B,KAAK,EAAE,SAAS;QACd,EAAE,EAAE,MAAM,CAAA;QACV,IAAI,EAAE,QAAQ,GAAG,YAAY,GAAG,YAAY,CAAA;QAC5C,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;QACzC,KAAK,EAAE,SAAS;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAE,EAAE,CAAA;QACnD,KAAK,EAAE,MAAM,CAAA;QACb,cAAc,EAAE,MAAM,CAAA;QACtB,gBAAgB,EAAE,MAAM,CAAA;KACzB,EAAE,CAAA;CACJ;AAKD,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,GAAG,SAAS,sBAAsB,EAAE,CAgC5F;AAYD,8GAA8G;AAC9G,qBAAa,eAAe;;gBAMd,OAAO,EAAE,sBAAsB;IAUrC,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,IAAI;;;;;;;;gBAqBtG,MAAM;4BAAkB,MAAM;mBAAS,MAAM;qBAAW,MAAM;uBAAa,OAAO;uBAAa,MAAM;+BAAqB,MAAM;iCAAuB,MAAM;;;;;;;;;;;;;IA6C5K,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAC7B"}