@deniscodp/skills 0.0.0-stage → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +89 -2
- package/bin/deniscodp-skills.mjs +4 -0
- package/package.json +23 -4
- package/scripts/catalog.mjs +68 -0
- package/scripts/cli.mjs +264 -0
- package/scripts/install.mjs +184 -0
- package/scripts/recommended.mjs +102 -0
- package/skills/denisco-handoff-implementation/SKILL.md +254 -0
- package/skills/denisco-handoff-implementation/references/blocker-checklist.md +71 -0
- package/skills/denisco-handoff-implementation/references/delegated-implementation.md +168 -0
- package/skills/denisco-handoff-implementation/references/ownership.md +105 -0
- package/skills/denisco-handoff-implementation/references/session-plan.md +195 -0
- package/skills/denisco-handoff-implementation/scripts/ownership.mjs +153 -0
- package/skills/denisco-implementation-coordinator/SKILL.md +237 -0
- package/skills/denisco-implementation-coordinator/agents/openai.yaml +2 -0
- package/skills/denisco-implementation-coordinator/references/documents.md +175 -0
- package/skills/denisco-implementation-coordinator/references/runtimes.md +105 -0
- package/skills/denisco-interactive-spec-definition/SKILL.md +126 -0
- package/skills/denisco-interactive-spec-definition/references/blocker-checklist.md +71 -0
- package/skills/denisco-interactive-spec-definition/references/handoff-template.md +124 -0
- package/skills/denisco-project-context/SKILL.md +60 -0
- package/skills/denisco-project-context/references/project-documents.md +70 -0
- package/skills/denisco-visual-check/SKILL.md +136 -0
- package/skills/denisco-visual-check/references/judge-prompt.md +55 -0
- package/skills/denisco-visual-check/references/project-config.md +118 -0
- package/skills/denisco-workflow-benchmark/SKILL.md +113 -0
- package/skills/denisco-workflow-benchmark/agents/openai.yaml +2 -0
- package/skills/denisco-workflow-benchmark/references/measurement.md +166 -0
- package/skills/denisco-workflow-benchmark/references/workflow-contract.md +371 -0
- package/skills/denisco-workflow-benchmark/scripts/bench.mjs +156 -0
- package/skills/denisco-workflow-benchmark/scripts/cases.mjs +46 -0
- package/skills/denisco-workflow-benchmark/scripts/configuration.mjs +71 -0
- package/skills/denisco-workflow-benchmark/scripts/discover.mjs +88 -0
- package/skills/denisco-workflow-benchmark/scripts/eval-worker.mjs +58 -0
- package/skills/denisco-workflow-benchmark/scripts/io.mjs +82 -0
- package/skills/denisco-workflow-benchmark/scripts/prepare.mjs +69 -0
- package/skills/denisco-workflow-benchmark/scripts/runs.mjs +235 -0
- package/skills/denisco-workflow-benchmark/scripts/state-prompt.mjs +96 -0
- package/skills/denisco-workflow-benchmark/scripts/tracking.mjs +91 -0
- package/skills/denisco-workflow-benchmark/scripts/usage.mjs +175 -0
- package/skills/denisco-workflow-benchmark/scripts/workflow.mjs +334 -0
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
# Persistent task measurement and closure
|
|
2
|
+
|
|
3
|
+
This contract applies to real tasks, not only isolated prepared cases. Use Node 20+ and the
|
|
4
|
+
installed skill's `scripts/bench.mjs`. No command launches a model. Commands with explicit write
|
|
5
|
+
targets require write authorization (including existing task authorization); Plan Mode may
|
|
6
|
+
read/check existing files, not bind, save/clear prompts or update records.
|
|
7
|
+
|
|
8
|
+
## Ownership and discovery
|
|
9
|
+
|
|
10
|
+
`<handoff-path>.workflow.json` is the durable entry point, discovered from the handoff alone.
|
|
11
|
+
denisco-handoff-implementation owns the planned block map; denisco-workflow-benchmark owns binding and measured
|
|
12
|
+
evidence in run.json. Keep explanatory progress in PLAN.md/STATE.md. The sidecar contains no
|
|
13
|
+
criterion outcomes, token counters or duplicate evidence history.
|
|
14
|
+
|
|
15
|
+
This ownership describes data responsibilities, not permission for concurrent writers. During
|
|
16
|
+
handoff planning/implementation, use denisco-handoff-implementation's worktree claim before any mutation,
|
|
17
|
+
including setup, `track`, `open`, `collect`, `report` and `close`. Native conversation keys and
|
|
18
|
+
registration tickets are accounting identities; two live processes may share them. They cannot
|
|
19
|
+
be used to bypass an execution claim. The implementation owner alone updates the run and sidecar; delegated
|
|
20
|
+
visual children return evidence for that principal to register. A conflicting instance uses
|
|
21
|
+
read-only inspection/checkpoint until an explicit ownership transfer, not a filesystem idle timer.
|
|
22
|
+
These CLI commands do not themselves intercept arbitrary writes or enforce the worktree claim;
|
|
23
|
+
the owning skill requires the guard and serializes their invocation.
|
|
24
|
+
|
|
25
|
+
The sidecar has `schemaVersion: 1`, project `taskId`, document paths `handoff`, `plan`, `state`,
|
|
26
|
+
`measurement`, and `blocks`. Document paths resolve relative to the sidecar. Each block has
|
|
27
|
+
`id`, nonempty `points` and `criteria` ID arrays, and a `dependsOn` block ID array (possibly empty).
|
|
28
|
+
IDs are unique within each array; dependency cycles are invalid. The complete map must cover
|
|
29
|
+
every required run criterion, including those of future/blocked blocks. A criterion can be shared
|
|
30
|
+
by blocks when the prepared plan requires it. Compare assignments against the handoff manually;
|
|
31
|
+
the script cannot detect a requirement that was never supplied or was mapped to the wrong block.
|
|
32
|
+
|
|
33
|
+
Measurement is `{ "status": "unknown" }`, `{ "status": "disabled" }`, or the enabled binding
|
|
34
|
+
generated below. Measurement is disabled by default and requires an explicit activation in the
|
|
35
|
+
current user request or applicable project instructions. Installation, criteria, an old register or
|
|
36
|
+
unknown status are not activation. Disabled is authoritative across later sessions. Unknown is
|
|
37
|
+
inert legacy/interrupted state and must not trigger setup without explicit activation evidence.
|
|
38
|
+
Never search unrelated project logs or registers.
|
|
39
|
+
|
|
40
|
+
## Agent-managed setup and first handoff
|
|
41
|
+
|
|
42
|
+
Only after explicit activation and once the handoff's criteria are agreed, reuse the bound or
|
|
43
|
+
explicitly referenced run. If none is referenced, follow the project's documented register location;
|
|
44
|
+
otherwise use `measurement/run.json`
|
|
45
|
+
alongside HANDOFF. The agent writes `measurement-criteria.json` alongside HANDOFF from the actual
|
|
46
|
+
agreed IDs/expectations, then runs `init --out <measurement-dir> --task <task-id> --project
|
|
47
|
+
<actual-project-root> --variant candidate --criteria <criteria-file>` and `bind`. Do not use dummy
|
|
48
|
+
criteria to start counting sooner. Inspect existing destinations; reuse a matching existing run
|
|
49
|
+
after checking project, task and the full criterion contract, or report a conflict without overwriting.
|
|
50
|
+
Bind preserves explicitly disabled measurement and does not itself change the default preference.
|
|
51
|
+
|
|
52
|
+
When measurement is explicitly enabled, run `track` before ending specification, even though
|
|
53
|
+
PLAN/STATE and blocks do not exist yet.
|
|
54
|
+
It can import the current conversation's earlier specification work from the same log. Mixed-task
|
|
55
|
+
histories require actual time bounds; a marker proves identity, not task scope. Earlier separate
|
|
56
|
+
conversations require independently evidenced attribution. Report gaps instead of assigning today's
|
|
57
|
+
ID to them. A specification abandoned before criteria/setup can remain unmeasured; do not hide that gap.
|
|
58
|
+
|
|
59
|
+
Save and check the planning prompt with `planning-prompt --handoff FILE --save` then `--check`.
|
|
60
|
+
Without flags it only prints. The helper validates the draft sidecar and binding, allows missing
|
|
61
|
+
PLAN/STATE and empty blocks, and appends its managed section to HANDOFF using the same protected
|
|
62
|
+
writer as STATE prompts. Existing handoff text is preserved. Mutually exclusive flags and invalid
|
|
63
|
+
markers are rejected; a missing/stale prompt check exits 2. It does not create a plan, approve one
|
|
64
|
+
or select a block. The response links the saved section and supplies its exact text. Without a
|
|
65
|
+
helper the specification skill saves/rereads the equivalent manually; Plan Mode leaves writes pending.
|
|
66
|
+
|
|
67
|
+
At first planning entry register that conversation through track, preserve existing decisions,
|
|
68
|
+
create/reconcile PLAN and STATE, and populate the complete planned block map. Resolve unresolved
|
|
69
|
+
blockers, select the first dependency-ready block and save/check its execution prompt before
|
|
70
|
+
asking the start question. If every block waits on a user action or a third party, record that in
|
|
71
|
+
STATE and stop without application edits.
|
|
72
|
+
|
|
73
|
+
Specification delivers HANDOFF, its sidecar and planning prompt, then asks whether to start
|
|
74
|
+
planning. Planning delivers PLAN/STATE, the block map and first execution prompt, then asks whether
|
|
75
|
+
to start implementation. Only the user's yes to that question, or a later submitted prompt or
|
|
76
|
+
explicitly scoped request, moves to the next phase in the same conversation; record the instruction
|
|
77
|
+
and scope without asking for a redundant approval. In Plan Mode propose that phase's deliverables;
|
|
78
|
+
once writing is permitted, materialize them and ask. Native plan approval, automatic mode and bare
|
|
79
|
+
transition text do not advance phases. Implementation then continues block by block until
|
|
80
|
+
denisco-handoff-implementation's real stop. A prompt found in a file is not a user request. Helpers prepare
|
|
81
|
+
and check artifacts; they never launch model sessions.
|
|
82
|
+
|
|
83
|
+
## Agent-managed session registration
|
|
84
|
+
|
|
85
|
+
```text
|
|
86
|
+
track --handoff FILE --provider codex|claude --phase PHASE [--root LOG_DIR]
|
|
87
|
+
[--from ISO --to ISO --parent KEY --parent-evidence TEXT --configuration ID|--skills-root DIR]
|
|
88
|
+
track --ticket FILE
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
The first call writes an internal ticket under the bound run's `registrations/` and records a
|
|
92
|
+
pending attempt in the run. It returns a generated marker and `nextCall` as an executable plus
|
|
93
|
+
argument array. The agent executes those arguments in a **separate tool call in the same
|
|
94
|
+
conversation**, quoting for its shell. This lets the first output reach the native transcript.
|
|
95
|
+
It also snapshots the provider's installed skill root (`<project>/.claude/skills` or
|
|
96
|
+
`<project>/.agents/skills`) when present and associates that snapshot with the new session.
|
|
97
|
+
No user-supplied session ID, log path or nonce is necessary. Never reuse a ticket in another
|
|
98
|
+
conversation or put it into a continuation prompt. Tickets contain local metadata, not messages.
|
|
99
|
+
|
|
100
|
+
The second call uses the marker and exact project to resolve one log and register/import it.
|
|
101
|
+
No/ambiguous matches return `pending` with a reason; retry once later in the same conversation,
|
|
102
|
+
then continue independent work with an explicit gap. Reports include pending attempts. A success
|
|
103
|
+
returns `sessionKey` and an internal ticket handle for checkpoint and close. Repeated calls preserve one session record and its
|
|
104
|
+
original phase; source, bounds, parent or supplied configuration conflicts stay pending. A child
|
|
105
|
+
requires the actual parent and evidence; do not guess it. The flags are internal agent operations.
|
|
106
|
+
|
|
107
|
+
The helper never confirms coverage or user acceptance. The agent reviews attribution, child logs
|
|
108
|
+
and configuration, records evidence, refreshes usage and generates the report. `collect` refreshes
|
|
109
|
+
registered logs only. An unchanged hash does not prove the conversation ended. After the final
|
|
110
|
+
response the last log may change; refresh at the next entry or from an observer with access to the
|
|
111
|
+
closed log, retaining a pending final-accounting note until then. No model is launched to do this.
|
|
112
|
+
Low-level discover/whoami/session remain available for evidence-based recovery; their IDs are not
|
|
113
|
+
part of the user's normal workflow.
|
|
114
|
+
|
|
115
|
+
## Bind an existing register
|
|
116
|
+
|
|
117
|
+
```text
|
|
118
|
+
bind --run <absolute-run.json> --handoff <file> [--task <project-task-id> --plan <file> --state <file>]
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Creates the sidecar if absent, with an empty block map and default adjacent PLAN.md/STATE.md.
|
|
122
|
+
When the sidecar exists, preserves its paths, project task ID and planned blocks. Optional path
|
|
123
|
+
arguments resolve from the command working directory, and conflicting arguments are rejected.
|
|
124
|
+
The command writes only the sidecar, never the handoff, plan, state or run. Bind can precede planning;
|
|
125
|
+
checkpoint/next-prompt require the actual documents and complete map.
|
|
126
|
+
|
|
127
|
+
The generated `measurement` stores `status: enabled`, absolute `run`, its `runId`, benchmark
|
|
128
|
+
`taskId`, and `criteriaHash` (canonical ID/expectation/required contract). The project task ID may
|
|
129
|
+
differ. Handoff must reside within run.project; worktree and main checkout are not interchangeable.
|
|
130
|
+
The agent selects the run from the task's binding or documented location, checking identity and criteria.
|
|
131
|
+
Binding is idempotent. A different run, changed criteria, explicitly disabled measurement or
|
|
132
|
+
conflicting existing paths stop before writes. Do not manually bypass conflicts by deleting the
|
|
133
|
+
sidecar; reconcile moved paths or approved scope changes with the user and preserve the history.
|
|
134
|
+
|
|
135
|
+
## Open and close a working session
|
|
136
|
+
|
|
137
|
+
```text
|
|
138
|
+
open --handoff <file> --block B2 [--phase implementation] [--nonce TOKEN]
|
|
139
|
+
close --handoff <file> --block B1 --implementation complete (--next-block B2 | --final)
|
|
140
|
+
[--ticket TICKET | --session-key provider:id --session-state closed --claim verified]
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
After setup and registration, `open` inspects an assigned block; `close` saves the continuation,
|
|
144
|
+
checkpoints and refreshes usage. They require existing documents and a complete planned map.
|
|
145
|
+
When the current conversation has a registered ticket, use `close --ticket` so the checkpoint
|
|
146
|
+
automatically reuses its session key. A ticket is valid only in the conversation that created it;
|
|
147
|
+
never transfer it to a later prompt.
|
|
148
|
+
The agent also generates report at closure. Usage is refreshed again at the next entry or by an
|
|
149
|
+
observer after the last response. A new conversation alone does not attest the old one's closure.
|
|
150
|
+
|
|
151
|
+
`open` retains low-level identity hints for compatibility. Prefer `track` to resolve and register
|
|
152
|
+
together. An unresolved identity stays pending; it is never replaced by the most recent log.
|
|
153
|
+
|
|
154
|
+
## Check a block without changing anything
|
|
155
|
+
|
|
156
|
+
```text
|
|
157
|
+
checkpoint --handoff <file> --block B1 --implementation complete
|
|
158
|
+
[--session-key provider:id --session-state active|closed|unknown --claim verified --next-block B2]
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Implementation is an explicit operator/agent declaration: `complete`, `in-progress`, or
|
|
162
|
+
`not-started`. It is not inferred from tests. The computed point status is respectively
|
|
163
|
+
`verified` only with all required passing, intact, fresh evidence; otherwise
|
|
164
|
+
`implemented-unverified`; or `in-progress`/`planned` for the latter two declarations.
|
|
165
|
+
Underlying verification retains failed/blocked/reopened/invalidated distinctions.
|
|
166
|
+
At least one required criterion is needed for automatic verified status; optional-only blocks
|
|
167
|
+
remain unverified. Missing criteria, artifacts, hashes or evidence after reopening never pass.
|
|
168
|
+
|
|
169
|
+
Optional `--claim` accepts planned, in-progress, implemented-unverified or verified. A conflicting
|
|
170
|
+
claim gives exit code 2 plus the calculated status. Without a claim, code 0 means the inspection
|
|
171
|
+
succeeded, not that the block passed. Invalid binding/map/links produce code 1.
|
|
172
|
+
With `--next-block B2`, it also performs the saved-prompt check below and returns `continuation`
|
|
173
|
+
with `valid` and `status`. A missing, stale or altered prompt gives code 2, even if the current
|
|
174
|
+
block is technically verified; technical `status`, `verification` and `claimMatches` are unchanged.
|
|
175
|
+
Omitting `--next-block` preserves the existing read-only behavior and does not check prompt delivery.
|
|
176
|
+
|
|
177
|
+
The output separates technical verification from session registration, log freshness and coverage.
|
|
178
|
+
Missing identity remains pending. `--session-state closed` is a declaration, not process detection
|
|
179
|
+
or coverage confirmation. Active/unknown sessions are provisional. A changed log needs collect;
|
|
180
|
+
unavailable logs and parser warnings remain explicit. Registering the session does not prove
|
|
181
|
+
subagent completeness. Checkpoint does not register/import anything automatically.
|
|
182
|
+
|
|
183
|
+
The command checks the entire map, then only the assigned block's verification. Future unfinished
|
|
184
|
+
blocks do not invalidate an otherwise verified B1. It shows dependency verification but does not
|
|
185
|
+
decide dependency readiness: review which missing checks actually prevent the next work.
|
|
186
|
+
Reconcile STATE.md and the final response with the calculated result. No arbitrary Markdown parser
|
|
187
|
+
claims to detect phrases like "verified except A5"; the agent must use the computed status.
|
|
188
|
+
Evidence hashes establish integrity, not semantic sufficiency. In ordinary projects, reopen and
|
|
189
|
+
reverify after code changes; this version does not fingerprint all business source automatically.
|
|
190
|
+
|
|
191
|
+
With disabled/unknown measurement, structural checks and prompt generation remain available,
|
|
192
|
+
but acceptance verification reports `not-checked` and cannot yield automatic verified status.
|
|
193
|
+
|
|
194
|
+
## Generate the next assigned prompt
|
|
195
|
+
|
|
196
|
+
```text
|
|
197
|
+
next-prompt --handoff <file> --block B2 [--save|--check]
|
|
198
|
+
next-prompt --handoff <file> --clear
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Without an option it prints a prompt only. No form chooses a block or launches a session.
|
|
202
|
+
Prepare the first execution prompt during planning, before execution is authorized. When the user
|
|
203
|
+
submits it as the next request, it continues the task from the named block. Generating or reading
|
|
204
|
+
a saved prompt does not authorize anything. Respect newer user restrictions; the helper does not
|
|
205
|
+
infer approval from arbitrary prose or intercept application-writing tools.
|
|
206
|
+
Requires a block from the planned map and existing documents. The prompt is short: absolute handoff,
|
|
207
|
+
state, plan and sidecar paths, the project task ID, the block's points, criteria and dependencies,
|
|
208
|
+
and the measurement status (with run path, both task IDs and accounting instructions only when
|
|
209
|
+
enabled). Task-specific constraints, blockers and Your actions stay in STATE outside the generated
|
|
210
|
+
section; the prompt tells the next session to read STATE first. Worktree ownership, evidence
|
|
211
|
+
reconciliation and authorization rules come from denisco-handoff-implementation itself; an inherited claim
|
|
212
|
+
token is never valid for a newly resumed process.
|
|
213
|
+
Unknown/disabled measurement is explicitly represented. Never use old external PROMPTS.md splits
|
|
214
|
+
to override the current PLAN.md and map.
|
|
215
|
+
|
|
216
|
+
`--save` writes and rereads the resolved STATE file, returning JSON with `state`, `block`, `changed`,
|
|
217
|
+
`valid`, `status: saved`, and the verified `prompt` (LF-normalized text). `--check` never writes:
|
|
218
|
+
it returns `valid` and `status: saved|missing|stale-or-modified`; a failed check gives exit code 2.
|
|
219
|
+
The prompt is returned only on a successful check. Both compare the actual saved section with
|
|
220
|
+
the current generator and structural context, including the complete block map and measurement
|
|
221
|
+
binding. Updating usage/results alone does not invalidate the prompt. Structural changes or a
|
|
222
|
+
changed generator require another explicit save. After a skill update, regenerate/check saved
|
|
223
|
+
planning prompts and prepared execution prompts with the installed helper; preserve surrounding
|
|
224
|
+
notes and approval evidence. This is not a semantic check of notes or PLAN prose.
|
|
225
|
+
|
|
226
|
+
The single managed section runs from `<!-- workflow:next-prompt:start -->` to
|
|
227
|
+
`<!-- workflow:next-prompt:end -->`, with a heading, a context fingerprint comment and a fenced
|
|
228
|
+
copyable prompt. Add it on first save, replace it on later saves. All text outside it is preserved,
|
|
229
|
+
including history; separation newlines may be added on first insertion. The writer preserves
|
|
230
|
+
UTF-8 (with/without BOM), BOM-marked UTF-16 LE/BE, and existing outside line endings; generated
|
|
231
|
+
text uses CRLF when present, otherwise LF. Invalid encoded text is rejected rather than repaired.
|
|
232
|
+
Repeated identical saves do not rewrite the file. Duplicate, partial or misordered markers are
|
|
233
|
+
errors (code 1), never a reason to overwrite the whole document. Repair malformed sections first.
|
|
234
|
+
Legacy unmarked prose is preserved; the agent reconciles obsolete manual prompts outside the section.
|
|
235
|
+
|
|
236
|
+
`--clear` requires no block and rejects `--block`. It removes only the managed section; absent
|
|
237
|
+
sections are an idempotent success. It returns `status: cleared`, `block: null`, `prompt: null`,
|
|
238
|
+
`valid: true` and `changed`. It declares no implementation/acceptance outcome. The three flags are
|
|
239
|
+
mutually exclusive. Saves/clears use a STATE lock, recheck source bytes/context, atomically replace
|
|
240
|
+
through a temporary file and reread the result. A live lock or detected concurrent change stops
|
|
241
|
+
the operation; inspect stale locks manually. Uncooperative writers cannot be prevented from editing
|
|
242
|
+
after the check, so use one writer and keep the closing check last.
|
|
243
|
+
|
|
244
|
+
At each block's end: finish validation, register evidence, reconcile STATE and run checkpoint for
|
|
245
|
+
that block. When the working session reaches a real stop: save/check the next assignment, then
|
|
246
|
+
checkpoint the last block worked with --next-block. Use the same block for unfinished implementation
|
|
247
|
+
or verification; its pending blockers live in STATE. Do not omit the continuation merely because no
|
|
248
|
+
new block exists or its future launch has not yet been authorized. The working programmer never
|
|
249
|
+
launches the saved continuation itself. An explicitly authorized denisco-implementation-coordinator may dispatch
|
|
250
|
+
the next bounded assignment under the recorded user scope; a worker never launches its successor.
|
|
251
|
+
Clear it only when no task work remains, or the user ends the task or asks for no prompt, retaining
|
|
252
|
+
acceptance and accounting gaps; a user stop with work remaining keeps it. After later code/evidence changes, refresh results and checkpoint again.
|
|
253
|
+
Disabled/unknown measurement supports these structural operations without creating a run.
|
|
254
|
+
In Plan Mode propose artifacts and leave writes pending. Without the helper save/reread manually.
|
|
255
|
+
The helper cannot force its invocation or prove that a user submitted a saved prompt.
|
|
256
|
+
|
|
257
|
+
## Configuration provenance across upgrades
|
|
258
|
+
|
|
259
|
+
```text
|
|
260
|
+
configuration --run <file> --skills-root <installed-flat-bundle> --note <provenance>
|
|
261
|
+
[--loaded denisco-handoff-implementation,denisco-workflow-benchmark]
|
|
262
|
+
session --run <file> ... --configuration <returned-ID>
|
|
263
|
+
session-config --run <file> --session-key provider:id --configuration <ID> --note <attribution>
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
`configuration` appends a uniquely identified snapshot to configurationHistory: capture/observation
|
|
267
|
+
time, provenance, package file hashes and declared metadata.version. It reads only current files;
|
|
268
|
+
it is not retrospective evidence for B1 after installing B2. It does not import repository tooling
|
|
269
|
+
or a YAML dependency. Simple two-space-indented metadata.version scalars are recognized; unfamiliar
|
|
270
|
+
YAML remains an explicit unknown with a hash, not an invented version. Repository YAML validation
|
|
271
|
+
is a separate stronger check.
|
|
272
|
+
|
|
273
|
+
Every package is installed-only unless named in `--loaded`, which is an operator attestation
|
|
274
|
+
requiring observed session/tool evidence in the note. Being installed is never proof of loading.
|
|
275
|
+
Neither recording a snapshot nor updating environment automatically attributes it to any session.
|
|
276
|
+
Associate snapshots only with supporting evidence; legacy sessions remain unknown if evidence is
|
|
277
|
+
unavailable. `session-config` requires a note and refuses to replace a different prior attribution.
|
|
278
|
+
Reimport preserves associations. Sessions that genuinely mix skill versions need explicit notes;
|
|
279
|
+
do not describe them as a clean single-version comparison.
|
|
280
|
+
|
|
281
|
+
`environment` now appends notes without losing the previous legacy environmentReview. Reports keep
|
|
282
|
+
the latest view plus histories and per-session configuration IDs. Skill version/hash changes are
|
|
283
|
+
visible across upgrades, not silently applied to earlier work. Existing schemaVersion 1 registers
|
|
284
|
+
remain readable without rewriting them or guessing missing associations.
|
|
285
|
+
|
|
286
|
+
## Working-session / operator boundary
|
|
287
|
+
|
|
288
|
+
The working session records real evidence and identified session IDs. If its own identity is not
|
|
289
|
+
available after the bounded retry, record the pending action for later evidence-based recovery;
|
|
290
|
+
do not ask the user to find IDs or choose the latest log blindly. One native session mixing planning
|
|
291
|
+
and implementation counts once under its registered phase.
|
|
292
|
+
After closure, collect and report finalize observed logs, while coverage still requires review.
|
|
293
|
+
Keep exploration separately visible. Measurement-only agent overhead is distinct from implementation.
|
|
294
|
+
Capture changes to the workflow configuration between blocks; different business blocks are not a
|
|
295
|
+
matched token-efficiency experiment. No helper authorizes paid runs, production writes or new tests.
|
|
296
|
+
|
|
297
|
+
## Visual checks and optional delegation
|
|
298
|
+
|
|
299
|
+
An optional sidecar visualChecks array identifies checks by unique id, block, nonempty criteria,
|
|
300
|
+
executor "principal" or "subagent", and optional required: false. New ordinary checks use principal.
|
|
301
|
+
Only an explicit user request delegates the whole check; a perceptual blind judge remains a separate
|
|
302
|
+
child used when applicable and permitted. Its result and native usage do not replace the executor.
|
|
303
|
+
|
|
304
|
+
Use visual-start --executor principal|subagent before capture, with --principal-session when known,
|
|
305
|
+
and visual-finish with --session-key of the executor, --loaded true|false, --results JSON and
|
|
306
|
+
--evidence files afterwards. Explicitly load denisco-visual-check and refresh the registered executor log
|
|
307
|
+
before finish. Principal checks require a top-level session matching the recorded principal;
|
|
308
|
+
delegated checks require a registered child whose parent matches that principal. Skill loading
|
|
309
|
+
must appear in the executor's native log (Skill tool or slash command). Missing proof remains
|
|
310
|
+
unverified; installation or an agent's assertion alone is insufficient.
|
|
311
|
+
|
|
312
|
+
For compatibility, omitting --executor retains the legacy subagent behavior; new workflow calls
|
|
313
|
+
always name principal or the user's requested subagent. Existing run records without executor are
|
|
314
|
+
read as legacy delegated attempts. Existing sidecars already name subagent and stay readable.
|
|
315
|
+
Do not relabel historical attempts to satisfy a new policy. For future checks reconcile an old
|
|
316
|
+
delegated assignment against the current user request, preserve history and choose a new attempt ID.
|
|
317
|
+
|
|
318
|
+
Checkpoint validates the executor, session attribution, block and passing results for all assigned
|
|
319
|
+
criteria. It never accepts principal evidence for an explicitly delegated assignment or vice versa.
|
|
320
|
+
Evidence relevance remains an agent responsibility. Finish also stores artifact hashes and duration.
|
|
321
|
+
Record criterion evidence through result as usual. With disabled measurement use STATE as the record.
|
|
322
|
+
|
|
323
|
+
Only the implementation owner updates shared state and the register. Delegated visual-only checkers write their exclusive
|
|
324
|
+
attempt directory; the principal merges index rows. Keep measured code/tooling stable during capture.
|
|
325
|
+
Close resources created solely for the check on success, failure or cancellation, preserving existing
|
|
326
|
+
services and explicitly needed follow-up resources. Close/release returned children where supported;
|
|
327
|
+
report cleanup limitations rather than claiming process exit.
|
|
328
|
+
|
|
329
|
+
Inspect existing evidence and native logs before scheduling a replacement. For Claude children,
|
|
330
|
+
the native JSONL is normally in the conversation's subagents directory: verify root sessionId and
|
|
331
|
+
agentId in its records, register with --id ROOT_ID --agent AGENT_ID and the evidenced parent.
|
|
332
|
+
A temporary task .output file is not the native transcript. Other providers require their actual
|
|
333
|
+
native identity and relationship. Include the blind judge separately; missing attribution leaves
|
|
334
|
+
coverage pending and never warrants inventing usage or launching a model just to count it.
|
|
335
|
+
|
|
336
|
+
## Coordinated execution
|
|
337
|
+
|
|
338
|
+
With denisco-implementation-coordinator explicitly authorized, follow denisco-handoff-implementation's bounded
|
|
339
|
+
assignment and ownership contract. Its preparation writes COORDINATOR, COORDINATOR-HISTORY and
|
|
340
|
+
packet files, then reaches a separate execution boundary. When planning selects the coordinated path,
|
|
341
|
+
planning and preparation share the planning registration. Register the coordinator before its actual native
|
|
342
|
+
children when measurement is enabled and bound: use planning for preparation or implementation for
|
|
343
|
+
an execution-only entry, with a coordination note. One native conversation spanning both phases
|
|
344
|
+
retains one registration with its actual history explained. Record overhead rather than hiding it.
|
|
345
|
+
Register a programming worker with its actual parent evidence. Each worker keeps its own ticket.
|
|
346
|
+
The worker owns the worktree and may update the run and sidecar; the coordinator only reads until
|
|
347
|
+
the worker finishes and releases. Parent registration failures leave child accounting pending and
|
|
348
|
+
never justify registering a native child as a top-level session. Independent implementation continues.
|
|
349
|
+
The coordinator may register/refresh/report measurement under its own claim between workers, but
|
|
350
|
+
never writes HANDOFF, PLAN, STATE, STATE-HISTORY or the sidecar, including through `close`, `bind`,
|
|
351
|
+
planning-prompt or next-prompt save/clear. Missing measurement setup or technical prompt repairs
|
|
352
|
+
belong to the standard worker workflow. Preserve pending attribution if setup cannot yet complete.
|
|
353
|
+
|
|
354
|
+
A programming worker performs its own visual checks. For a native child use executor `subagent`,
|
|
355
|
+
the worker's session key and its actual parent as principal session. The initial explicit request
|
|
356
|
+
to coordinate implementation includes its required checks. Reconcile future sidecar visualChecks
|
|
357
|
+
entries accordingly; preserve historical attempts. This changes no executor validation rules:
|
|
358
|
+
operational ownership is distinct from native parentage. Register a blind judge under its actual
|
|
359
|
+
caller, including when the coordinator relays a blind packet for a worker unable to spawn children.
|
|
360
|
+
Visual-only checkers retain their exclusive artifact scope and never write shared registers.
|
|
361
|
+
|
|
362
|
+
Keep the bounded assignment and coordinator launch/resume prompt in COORDINATOR, with coordination
|
|
363
|
+
events in COORDINATOR-HISTORY. The programmer reads those files and updates only technical documents
|
|
364
|
+
through denisco-handoff-implementation; the coordinator never appends technical history on its behalf.
|
|
365
|
+
STATE contains the short coordination reference and its ordinary generated next-prompt section.
|
|
366
|
+
The helper still generates a generic starting-block prompt; the coordinator supplies the exact
|
|
367
|
+
allowed block list and return boundary separately. After the final implementation block, retain
|
|
368
|
+
that block as the continuation anchor while STATE names pending integration; clear only when no
|
|
369
|
+
task work remains or the user explicitly cancels. Existing helpers do not launch workers or prove
|
|
370
|
+
that they respected their range. Cumulative usage is not live context occupancy; coordination does
|
|
371
|
+
not activate measurement when the sidecar is disabled.
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { requireValue, readJSON, writeJSON, loadRun, mutateRun, now } from './io.mjs';
|
|
6
|
+
import { createRun, registerSession, collect, recordEvidence, evaluate, report, compare, startVisualCheck, finishVisualCheck } from './runs.mjs';
|
|
7
|
+
import { prepare, checkProtected } from './prepare.mjs';
|
|
8
|
+
import { discover, whoami } from './discover.mjs';
|
|
9
|
+
import { bind, checkpoint, close, nextPrompt, open, planningPrompt } from './workflow.mjs';
|
|
10
|
+
import { track } from './tracking.mjs';
|
|
11
|
+
import { captureConfiguration, attachConfiguration, recordEnvironment } from './configuration.mjs';
|
|
12
|
+
|
|
13
|
+
const HELP = `Workflow benchmark (Node 20+, no model launches)
|
|
14
|
+
track --handoff FILE --provider codex|claude --phase PHASE [--root LOG_DIR]
|
|
15
|
+
[--from ISO --to ISO --parent KEY --parent-evidence TEXT --configuration ID|--skills-root DIR]
|
|
16
|
+
track --ticket FILE
|
|
17
|
+
planning-prompt --handoff FILE [--save|--check]
|
|
18
|
+
open --handoff FILE --block ID [--phase PHASE] [--provider codex|claude] [--nonce TOKEN]
|
|
19
|
+
close --handoff FILE --block ID --implementation complete|in-progress|not-started
|
|
20
|
+
(--next-block ID | --final) [--ticket FILE|--session-key provider:id] [--session-state STATE --claim STATUS]
|
|
21
|
+
whoami --provider codex|claude --nonce TOKEN [--project DIR --root LOG_DIR]
|
|
22
|
+
discover --provider codex|claude --project DIR [--root LOG_DIR --limit 20]
|
|
23
|
+
init --out DIR --task ID --project DIR --variant NAME --criteria JSON
|
|
24
|
+
bind --run FILE --handoff FILE [--task PROJECT_TASK --plan FILE --state FILE]
|
|
25
|
+
checkpoint --handoff FILE --block ID --implementation complete|in-progress|not-started
|
|
26
|
+
[--session-key provider:id --session-state active|closed|unknown --claim STATUS --next-block ID]
|
|
27
|
+
next-prompt --handoff FILE --block ID [--save|--check]
|
|
28
|
+
next-prompt --handoff FILE --clear
|
|
29
|
+
configuration --run FILE --skills-root DIR --note TEXT [--loaded name,name]
|
|
30
|
+
session-config --run FILE --session-key provider:id --configuration ID --note TEXT
|
|
31
|
+
prepare --out DIR --case order-filter|order-summary --variant baseline|candidate
|
|
32
|
+
--provider codex|claude [--baseline MANIFEST]
|
|
33
|
+
session --run FILE --provider codex|claude --id NATIVE_ID --log JSONL --phase PHASE
|
|
34
|
+
[--from ISO --to ISO] [--agent ID --parent provider:id --parent-evidence TEXT] [--coverage-confirmed] [--configuration ID]
|
|
35
|
+
visual-start --run FILE --id ATTEMPT --block ID --criteria ID[,ID] [--executor principal|subagent] [--principal-session KEY] [--at ISO]
|
|
36
|
+
visual-finish --run FILE --id ATTEMPT --session-key EXECUTOR_KEY --loaded true|false [--results JSON] [--evidence FILE[,FILE]] [--at ISO]
|
|
37
|
+
collect --run FILE [--coverage-confirmed]
|
|
38
|
+
result --run FILE --criterion ID --status pass|fail|not-run --observation TEXT [--evidence FILE]
|
|
39
|
+
review --run FILE --status accepted|reopened|pending --note TEXT
|
|
40
|
+
environment --run FILE --note TEXT
|
|
41
|
+
intervention --run FILE --kind clarification|correction|approval|environment --note TEXT
|
|
42
|
+
evaluate --run FILE
|
|
43
|
+
report --run FILE
|
|
44
|
+
compare --runs FILE,FILE [--out JSON]
|
|
45
|
+
Phases: exploration, specification, planning, implementation, verification, correction.
|
|
46
|
+
Options use separate values; quote paths with spaces. Log paths and native IDs are explicit.
|
|
47
|
+
`;
|
|
48
|
+
const allowed = {
|
|
49
|
+
track: ['handoff', 'provider', 'phase', 'root', 'ticket', 'from', 'to', 'parent', 'parent-evidence', 'configuration', 'skills-root'],
|
|
50
|
+
'planning-prompt': ['handoff', 'save', 'check'],
|
|
51
|
+
bind: ['run', 'handoff', 'task', 'plan', 'state'],
|
|
52
|
+
open: ['handoff', 'block', 'phase', 'nonce', 'provider'],
|
|
53
|
+
close: ['handoff', 'block', 'implementation', 'next-block', 'final', 'session-key', 'session-state', 'claim', 'ticket'],
|
|
54
|
+
whoami: ['provider', 'project', 'nonce', 'root'],
|
|
55
|
+
checkpoint: ['handoff', 'block', 'implementation', 'session-key', 'session-state', 'claim', 'next-block'],
|
|
56
|
+
'next-prompt': ['handoff', 'block', 'save', 'check', 'clear'],
|
|
57
|
+
configuration: ['run', 'skills-root', 'note', 'loaded'],
|
|
58
|
+
'session-config': ['run', 'session-key', 'configuration', 'note'],
|
|
59
|
+
discover: ['provider', 'project', 'root', 'limit'],
|
|
60
|
+
init: ['out', 'task', 'project', 'variant', 'criteria'],
|
|
61
|
+
prepare: ['out', 'case', 'variant', 'provider', 'baseline'],
|
|
62
|
+
session: ['run', 'provider', 'id', 'agent', 'log', 'phase', 'from', 'to', 'parent', 'parent-evidence', 'coverage-confirmed', 'configuration'],
|
|
63
|
+
'visual-start': ['run', 'id', 'block', 'criteria', 'executor', 'principal-session', 'at'],
|
|
64
|
+
'visual-finish': ['run', 'id', 'session-key', 'loaded', 'results', 'evidence', 'at'],
|
|
65
|
+
collect: ['run', 'coverage-confirmed'], result: ['run', 'criterion', 'status', 'observation', 'evidence'],
|
|
66
|
+
review: ['run', 'status', 'note'], environment: ['run', 'note'], intervention: ['run', 'kind', 'note'],
|
|
67
|
+
evaluate: ['run'], report: ['run'], compare: ['runs', 'out']
|
|
68
|
+
};
|
|
69
|
+
export function main(args) {
|
|
70
|
+
const [command, ...rest] = args;
|
|
71
|
+
if (!command || ['help', '--help'].includes(command)) return HELP;
|
|
72
|
+
if (!allowed[command]) throw new Error(`Unknown command: ${command}`);
|
|
73
|
+
const opts = {};
|
|
74
|
+
for (let i = 0; i < rest.length; i++) {
|
|
75
|
+
const key = rest[i].slice(2);
|
|
76
|
+
if (!rest[i].startsWith('--') || !allowed[command].includes(key) || key in opts) throw new Error(`Invalid/duplicate option ${rest[i]}`);
|
|
77
|
+
opts[key] = ['coverage-confirmed', 'save', 'check', 'clear', 'final'].includes(key) ? true : requireValue(rest[++i], key);
|
|
78
|
+
}
|
|
79
|
+
const need = name => requireValue(opts[name], `--${name}`);
|
|
80
|
+
if (command === 'track') return track({ handoff: opts.handoff, provider: opts.provider, phase: opts.phase,
|
|
81
|
+
root: opts.root, ticket: opts.ticket, from: opts.from, to: opts.to, parent: opts.parent,
|
|
82
|
+
parentEvidence: opts['parent-evidence'], configurationId: opts.configuration, skillsRoot: opts['skills-root'] });
|
|
83
|
+
if (command === 'planning-prompt') {
|
|
84
|
+
const result = planningPrompt({ handoff: need('handoff'), save: opts.save, check: opts.check });
|
|
85
|
+
if (result.valid === false) process.exitCode = 2;
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
if (command === 'open') {
|
|
89
|
+
const result = open({ handoff: need('handoff'), block: need('block'), phase: opts.phase, nonce: opts.nonce, provider: opts.provider });
|
|
90
|
+
if (result.continuation.valid === false) process.exitCode = 2;
|
|
91
|
+
return result;
|
|
92
|
+
}
|
|
93
|
+
if (command === 'close') {
|
|
94
|
+
const result = close({ handoff: need('handoff'), block: need('block'), implementation: need('implementation'),
|
|
95
|
+
nextBlock: opts['next-block'], final: opts.final ?? false, sessionKey: opts['session-key'],
|
|
96
|
+
sessionState: opts['session-state'], claim: opts.claim, ticket: opts.ticket });
|
|
97
|
+
if (!result.claimMatches || result.continuation?.valid === false) process.exitCode = 2;
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
if (command === 'whoami') return whoami({ provider: need('provider'), project: opts.project, nonce: need('nonce'), root: opts.root });
|
|
101
|
+
if (command === 'bind') return bind({ handoff: need('handoff'), run: need('run'), task: opts.task, plan: opts.plan, state: opts.state });
|
|
102
|
+
if (command === 'checkpoint') {
|
|
103
|
+
const result = checkpoint({ handoff: need('handoff'), block: need('block'), implementation: need('implementation'), sessionKey: opts['session-key'], sessionState: opts['session-state'], claim: opts.claim, nextBlock: opts['next-block'] });
|
|
104
|
+
if (!result.claimMatches || result.continuation?.valid === false) process.exitCode = 2;
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
if (command === 'next-prompt') {
|
|
108
|
+
const result = nextPrompt({ handoff: need('handoff'), block: opts.clear ? opts.block : need('block'), save: opts.save, check: opts.check, clear: opts.clear });
|
|
109
|
+
if (result.valid === false) process.exitCode = 2;
|
|
110
|
+
return result;
|
|
111
|
+
}
|
|
112
|
+
if (command === 'configuration') return captureConfiguration(need('run'), { skillsRoot: need('skills-root'), note: need('note'), loaded: opts.loaded?.split(',') ?? [] });
|
|
113
|
+
if (command === 'session-config') return attachConfiguration(need('run'), { sessionKey: need('session-key'), configurationId: need('configuration'), note: need('note') });
|
|
114
|
+
if (command === 'discover') return discover({ provider: need('provider'), project: need('project'), root: opts.root, limit: opts.limit === undefined ? 20 : Number(opts.limit) });
|
|
115
|
+
if (command === 'init') return createRun({ out: need('out'), task: need('task'), project: need('project'), variant: need('variant'), criteria: readJSON(need('criteria')) });
|
|
116
|
+
if (command === 'prepare') return prepare({ out: need('out'), caseId: need('case'), variant: need('variant'), provider: need('provider'), baseline: opts.baseline });
|
|
117
|
+
if (command === 'session') return registerSession(need('run'), { provider: need('provider'), sessionId: need('id'), agentId: opts.agent, log: need('log'), phase: need('phase'), from: opts.from, to: opts.to, parent: opts.parent, parentEvidence: opts['parent-evidence'], coverageConfirmed: opts['coverage-confirmed'] ?? false, configurationId: opts.configuration });
|
|
118
|
+
if (command === 'visual-start') return startVisualCheck(need('run'), { id: need('id'), block: need('block'), criteria: need('criteria').split(','), executor: opts.executor, principalSession: opts['principal-session'], at: opts.at });
|
|
119
|
+
if (command === 'visual-finish') {
|
|
120
|
+
if (!['true', 'false'].includes(need('loaded'))) throw new Error('--loaded must be true or false');
|
|
121
|
+
return finishVisualCheck(need('run'), { id: need('id'), sessionKey: need('session-key'), skillLoaded: opts.loaded === 'true', results: opts.results ? readJSON(opts.results) : [], evidence: opts.evidence ? opts.evidence.split(',') : [], at: opts.at });
|
|
122
|
+
}
|
|
123
|
+
if (command === 'collect') return collect(need('run'), { coverageConfirmed: opts['coverage-confirmed'] ?? false });
|
|
124
|
+
if (command === 'result') return recordEvidence(need('run'), { criterion: need('criterion'), status: need('status'), observation: need('observation'), evidence: opts.evidence });
|
|
125
|
+
if (command === 'review') {
|
|
126
|
+
if (!['accepted', 'reopened', 'pending'].includes(need('status'))) throw new Error('Invalid review status');
|
|
127
|
+
return mutateRun(need('run'), run => {
|
|
128
|
+
const event = { type: opts.status, note: need('note'), at: now(), evidenceCount: run.evidence.length };
|
|
129
|
+
run.history.push(event); run.review = { status: opts.status, note: opts.note, at: event.at };
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
if (command === 'environment') return recordEnvironment(need('run'), need('note'));
|
|
133
|
+
if (command === 'intervention') {
|
|
134
|
+
if (!['clarification', 'correction', 'approval', 'environment'].includes(need('kind'))) throw new Error('Invalid intervention kind');
|
|
135
|
+
return mutateRun(need('run'), run => { run.interventions.push({ kind: opts.kind, note: need('note'), at: now() }); });
|
|
136
|
+
}
|
|
137
|
+
if (command === 'evaluate') {
|
|
138
|
+
const run = loadRun(need('run')), changed = checkProtected(run);
|
|
139
|
+
if (changed.length) throw new Error(`Benchmark contaminated: protected files changed: ${changed.join(', ')}`);
|
|
140
|
+
const result = evaluate(opts.run);
|
|
141
|
+
if (!result.passed) process.exitCode = 2;
|
|
142
|
+
return result;
|
|
143
|
+
}
|
|
144
|
+
if (command === 'report') return report(need('run'));
|
|
145
|
+
if (command === 'compare') {
|
|
146
|
+
const files = need('runs').split(',');
|
|
147
|
+
if (files.length < 2) throw new Error('At least two runs are required');
|
|
148
|
+
const result = compare(files);
|
|
149
|
+
if (opts.out) writeJSON(opts.out, result);
|
|
150
|
+
return result;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
154
|
+
try { const result = main(process.argv.slice(2)); console.log(typeof result === 'string' ? result : JSON.stringify(result, null, 2)); }
|
|
155
|
+
catch (e) { console.error(e.message); process.exitCode = 1; }
|
|
156
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export const CASES = {
|
|
2
|
+
'order-filter': {
|
|
3
|
+
title: 'Bug: filtro ordini coerente tra dashboard ed esportazione',
|
|
4
|
+
criteria: [
|
|
5
|
+
{ id: 'filter', expectation: 'Il filtro restituisce soltanto gli ordini dello stato richiesto.' },
|
|
6
|
+
{ id: 'consumers', expectation: 'Dashboard ed esportazione usano la stessa regola corretta.' },
|
|
7
|
+
{ id: 'regression', expectation: 'All, input vuoto, ordine originale e dati non mutati restano corretti.' }
|
|
8
|
+
],
|
|
9
|
+
files: {
|
|
10
|
+
'src/orders.mjs': `export function filterOrders(orders, status = 'all') {\n return status === 'all' ? [...orders] : orders.filter(order => order.status !== status);\n}\n`,
|
|
11
|
+
'src/dashboard.mjs': `import { filterOrders } from './orders.mjs';\nexport const dashboardOrders = (orders, status) => filterOrders(orders, status);\n`,
|
|
12
|
+
'src/export.mjs': `import { filterOrders } from './orders.mjs';\nexport const exportOrders = (orders, status) => filterOrders(orders, status);\n`
|
|
13
|
+
},
|
|
14
|
+
reference: {
|
|
15
|
+
'src/orders.mjs': `export function filterOrders(orders, status = 'all') {\n return status === 'all' ? [...orders] : orders.filter(order => order.status === status);\n}\n`
|
|
16
|
+
},
|
|
17
|
+
points: `## P1 — Correggere il filtro condiviso\n\nReady. Il comportamento atteso è uguaglianza dello stato, non esclusione. Riproduzione: tre ordini pending/completed/cancelled, filtro completed: deve restare solo completed. La causa è l'operatore in src/orders.mjs, filterOrders.\n\nRiutilizzare filterOrders per entrambi i consumatori src/dashboard.mjs e src/export.mjs. Non mutare input o ordine degli elementi. All restituisce tutti gli ordini; uno stato assente restituisce un array vuoto. Nessuna modifica backend esterna, UI o nuovo requisito visuale. Difficoltà verde, dipendenze nessuna.\n`
|
|
18
|
+
},
|
|
19
|
+
'order-summary': {
|
|
20
|
+
title: 'Feature: riepilogo ordini condiviso',
|
|
21
|
+
criteria: [
|
|
22
|
+
{ id: 'summary', expectation: 'summarizeOrders restituisce total e byStatus per pending/completed/cancelled.' },
|
|
23
|
+
{ id: 'consumers', expectation: 'dashboardSummary ed exportSummary restituiscono il riepilogo condiviso.' },
|
|
24
|
+
{ id: 'regression', expectation: 'Zero per categorie vuote; filtri precedenti e input restano invariati.' }
|
|
25
|
+
],
|
|
26
|
+
files: {
|
|
27
|
+
'src/orders.mjs': `export function filterOrders(orders, status = 'all') {\n return status === 'all' ? [...orders] : orders.filter(order => order.status === status);\n}\n`,
|
|
28
|
+
'src/dashboard.mjs': `import { filterOrders } from './orders.mjs';\nexport const dashboardOrders = (orders, status) => filterOrders(orders, status);\n`,
|
|
29
|
+
'src/export.mjs': `import { filterOrders } from './orders.mjs';\nexport const exportOrders = (orders, status) => filterOrders(orders, status);\n`
|
|
30
|
+
},
|
|
31
|
+
reference: {
|
|
32
|
+
'src/orders.mjs': `export function filterOrders(orders, status = 'all') {\n return status === 'all' ? [...orders] : orders.filter(order => order.status === status);\n}\nexport function summarizeOrders(orders) {\n const byStatus = { pending: 0, completed: 0, cancelled: 0 };\n for (const order of orders) byStatus[order.status]++;\n return { total: orders.length, byStatus };\n}\n`,
|
|
33
|
+
'src/dashboard.mjs': `import { filterOrders, summarizeOrders } from './orders.mjs';\nexport const dashboardOrders = (orders, status) => filterOrders(orders, status);\nexport const dashboardSummary = orders => summarizeOrders(orders);\n`,
|
|
34
|
+
'src/export.mjs': `import { filterOrders, summarizeOrders } from './orders.mjs';\nexport const exportOrders = (orders, status) => filterOrders(orders, status);\nexport const exportSummary = orders => summarizeOrders(orders);\n`
|
|
35
|
+
},
|
|
36
|
+
points: `## P1 — Aggiungere la regola pura\n\nReady. Esportare summarizeOrders(orders) da src/orders.mjs. Input: array di ordini con status tra pending, completed e cancelled; valori fuori contratto esclusi. Output esatto: { total: numero, byStatus: { pending: numero, completed: numero, cancelled: numero } }. Categorie assenti e input vuoto hanno zero; non mutare gli ordini. Il riepilogo riguarda tutti gli ordini passati, non un filtro implicito. Difficoltà gialla, nessuna dipendenza.\n\n## P2 — Collegare i consumatori\n\nReady. Esportare dashboardSummary da src/dashboard.mjs ed exportSummary da src/export.mjs; entrambe accettano orders e restituiscono il contratto di P1. Riutilizzare la regola condivisa. Conservare le funzioni filtro precedenti. Difficoltà verde, dipende da P1. Nessuna nuova UI, persistenza o servizio esterno.\n`
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export function handoff(caseId) {
|
|
41
|
+
const c = CASES[caseId];
|
|
42
|
+
if (!c) throw new Error('Unknown case');
|
|
43
|
+
return `Execute this document with the installed handoff implementation skill. Visual checks are not applicable to this headless task.\n\n# ${c.title}\n\nTask: ${caseId}. This is decided target behavior; no product decisions remain.\n\nBaseline: src/orders.mjs contains a shared filter consumed by dashboard and export. Follow AGENTS.md.\n\n${c.points}\n## Acceptance\n\n${c.criteria.map(x => `- ${x.id}: ${x.expectation}`).join('\n')}\n\nVerification: run node smoke.mjs, plus focused tests you add for these acceptance rules. The operator runs the external fixed evaluator after implementation; do not inspect it or reference solutions. No browser or login is needed.\n`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const smoke = `import assert from 'node:assert/strict';\nimport { filterOrders } from './src/orders.mjs';\nassert.deepEqual(filterOrders([]), []);\nconsole.log('Existing smoke check passed; acceptance checks are additional.');\n`;
|