@ishlabs/cli 0.20.0 → 0.22.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/dist/commands/chat.js +2 -2
- package/dist/commands/config.js +17 -3
- package/dist/commands/source.js +1 -1
- package/dist/commands/study-analyze.js +15 -2
- package/dist/commands/study-participant.js +19 -0
- package/dist/commands/study.js +313 -14
- package/dist/lib/alias-store.d.ts +1 -0
- package/dist/lib/alias-store.js +2 -0
- package/dist/lib/command-helpers.js +4 -3
- package/dist/lib/docs.js +232 -15
- package/dist/lib/output.d.ts +24 -1
- package/dist/lib/output.js +290 -2
- package/dist/lib/skill-content.js +76 -0
- package/dist/lib/study-participants.d.ts +13 -0
- package/dist/lib/study-participants.js +13 -0
- package/dist/lib/study-results-filters.d.ts +91 -0
- package/dist/lib/study-results-filters.js +559 -0
- package/dist/lib/study-results-projections.d.ts +152 -0
- package/dist/lib/study-results-projections.js +580 -0
- package/package.json +1 -1
package/dist/lib/docs.js
CHANGED
|
@@ -315,6 +315,8 @@ pick was wrong.
|
|
|
315
315
|
- \`concepts/assignment\` — task definition syntax.
|
|
316
316
|
- \`concepts/questionnaire\` — question types and timing.
|
|
317
317
|
- \`concepts/run-verbs\` — when to use \`study run\` vs \`ask run\`.
|
|
318
|
+
- \`guides/slicing-results\` — filter / project \`study results\` by frame,
|
|
319
|
+
segment, turn, sentiment, assignment, step.
|
|
318
320
|
- \`reference/billing-limits\` — \`maxStudiesPerProduct\` cap on study creation.
|
|
319
321
|
- \`reference/credits\` — per-run credit cost & how to preview before dispatch.
|
|
320
322
|
`;
|
|
@@ -633,7 +635,7 @@ Tunables (both modes):
|
|
|
633
635
|
the parties signal the conversation is over.
|
|
634
636
|
|
|
635
637
|
Pair-mode rules:
|
|
636
|
-
- Each side needs **either** \`--
|
|
638
|
+
- Each side needs **either** \`--group-a\` / \`--group-b\` (explicit IDs) **or**
|
|
637
639
|
\`--role-criteria-*\` (filter the backend resolves). The two can also
|
|
638
640
|
be combined — criteria then acts as validation on the explicit list.
|
|
639
641
|
- When both sides use explicit \`--group-a\` / \`--group-b\`, they
|
|
@@ -655,7 +657,7 @@ Pair-mode rules:
|
|
|
655
657
|
\`type\` field in \`--questionnaire\` / \`--questions\` manifests
|
|
656
658
|
(\`single-choice\` ↔ \`single_choice\`).
|
|
657
659
|
- Audiences are pinned to the iteration. \`ish study run\` refuses
|
|
658
|
-
run-time people overrides (\`--
|
|
660
|
+
run-time people overrides (\`--person\` / \`--sample\` / \`--all\` /
|
|
659
661
|
filters) on a pair iteration — change the peoples via
|
|
660
662
|
\`ish iteration update <id> --details-json '{...}'\` instead.
|
|
661
663
|
- \`--max-turns\` / \`--early-termination\` on \`ish study run\` override
|
|
@@ -851,6 +853,9 @@ ride along when present in the JSON forms.
|
|
|
851
853
|
|
|
852
854
|
- \`concepts/study\` — assignments are immutable to the run; questionnaire is too.
|
|
853
855
|
- \`concepts/questionnaire\` — the other half of the study definition.
|
|
856
|
+
- \`guides/slicing-results\` — slice the post-run envelope by step
|
|
857
|
+
(\`--step verify-email --group-by step\`), surface per-participant verdicts
|
|
858
|
+
inline, or restrict to the evidence interactions with \`--include-evidence\`.
|
|
854
859
|
- \`reference/json-mode\` — how \`step_completion\` renders in lean vs --verbose.
|
|
855
860
|
`;
|
|
856
861
|
const CONCEPT_QUESTIONNAIRE = `# concept: questionnaire
|
|
@@ -1127,7 +1132,7 @@ deleted ask was the active one.
|
|
|
1127
1132
|
- \`concepts/round\` — what a round is and how it executes.
|
|
1128
1133
|
- \`concepts/people\` — how participants are chosen at ask creation.
|
|
1129
1134
|
- \`concepts/run-verbs\` — \`ish ask run\` vs \`ish study run\`.
|
|
1130
|
-
- \`reference/credits\` — ask rounds bill
|
|
1135
|
+
- \`reference/credits\` — ask rounds bill **one credit per successful participant per round**, regardless of how many \`questions\` were included. The backend's asks worker bills \`amount=succeeded\` once per round dispatch; questions and round-summary synthesis don't trigger separate debits. A 3-person panel with 2 follow-up questions costs \`3\` credits when all complete, the same as a no-questions run. Failed participant responses (pre-flight errors, refusals) don't bill.
|
|
1131
1136
|
`;
|
|
1132
1137
|
const CONCEPT_ROUND = `# concept: round
|
|
1133
1138
|
|
|
@@ -1169,7 +1174,7 @@ const CONCEPT_PROFILE = `# concept: person
|
|
|
1169
1174
|
A **person** is a reusable persona — the simulated
|
|
1170
1175
|
human whose behaviour drives a participant instance during a study or ask.
|
|
1171
1176
|
|
|
1172
|
-
- Alias prefix: \`
|
|
1177
|
+
- Alias prefix: \`p-\`
|
|
1173
1178
|
- Lives at the workspace level, reusable across studies and asks.
|
|
1174
1179
|
- Distinct from a "participant" (\`pt-\`) — a participant is one *instance* of a
|
|
1175
1180
|
profile inside one iteration.
|
|
@@ -1331,7 +1336,7 @@ A **source** is an input to \`ish person generate\`: a transcript,
|
|
|
1331
1336
|
audio file, image, or PDF that an LLM reads to ground generated profiles
|
|
1332
1337
|
in real customer evidence.
|
|
1333
1338
|
|
|
1334
|
-
- Alias prefix: \`
|
|
1339
|
+
- Alias prefix: \`ps-\`
|
|
1335
1340
|
- Source kinds: \`text_file | audio | image\` (auto-detected from extension; \`text-file\` is accepted as a hyphen variant).
|
|
1336
1341
|
- Audio supports speaker diarization via \`--diarize\`.
|
|
1337
1342
|
|
|
@@ -1401,7 +1406,7 @@ flags. Two ways to select:
|
|
|
1401
1406
|
\`platform\` until the next release with a server-side
|
|
1402
1407
|
deprecation warning)
|
|
1403
1408
|
|
|
1404
|
-
The two modes are **mutually exclusive** — pass either \`--
|
|
1409
|
+
The two modes are **mutually exclusive** — pass either \`--person\` or
|
|
1405
1410
|
the filter set, not both.
|
|
1406
1411
|
|
|
1407
1412
|
## Empty-pool suggestions
|
|
@@ -1653,7 +1658,7 @@ and what they target differ.
|
|
|
1653
1658
|
| Default | latest iteration of the active study | append a round to the active ask |
|
|
1654
1659
|
| Fresh setup | \`ish iteration create …\` first, then run | \`--new\` (creates ask + round 1 in one shot) |
|
|
1655
1660
|
| Specific target| \`--iteration <id>\` | positional ask id (\`a-6ec\`) |
|
|
1656
|
-
| Audience | \`--
|
|
1661
|
+
| Audience | \`--person\` OR filters with \`--sample\`/\`--all\` — else reuse iteration's participants | only at \`--new\`; fixed for the ask afterwards |
|
|
1657
1662
|
| Output unit | per-participant interactions + questionnaire answers | per-participant reactions per round |
|
|
1658
1663
|
|
|
1659
1664
|
## Decision rule
|
|
@@ -1741,7 +1746,7 @@ When extend is **not** the right verb:
|
|
|
1741
1746
|
- Source participant is still RUNNING. \`cancel\` it first, then extend.
|
|
1742
1747
|
Extend refuses non-terminal sources server-side.
|
|
1743
1748
|
- You want a fresh cohort with new people flags. Use \`study run\`
|
|
1744
|
-
with \`--
|
|
1749
|
+
with \`--person\` / \`--sample\` / \`--all\` instead — extend is a
|
|
1745
1750
|
per-participant resume, not a batch op.
|
|
1746
1751
|
- You want to change the iteration's URL or content. Edit the iteration
|
|
1747
1752
|
itself (\`iteration update\` or a fresh iteration) — extend always
|
|
@@ -1901,8 +1906,8 @@ time the CLI sees an entity.
|
|
|
1901
1906
|
- \`s-\` study
|
|
1902
1907
|
- \`i-\` iteration
|
|
1903
1908
|
- \`pt-\` participant (instance of a person in an iteration)
|
|
1904
|
-
- \`
|
|
1905
|
-
- \`
|
|
1909
|
+
- \`p-\` person
|
|
1910
|
+
- \`ps-\` person source
|
|
1906
1911
|
- \`a-\` ask
|
|
1907
1912
|
- \`r-\` ask round
|
|
1908
1913
|
- \`c-\` config (simulation config)
|
|
@@ -2418,7 +2423,7 @@ not branch on \`status: 0\` — that value is never emitted as of 0.20.
|
|
|
2418
2423
|
- Lists print as JSON arrays (or paginated wrappers). Single resources
|
|
2419
2424
|
as JSON objects.
|
|
2420
2425
|
- Field names match the underlying API resource (snake_case).
|
|
2421
|
-
- Aliases (\`s-…\`, \`a-…\`, \`
|
|
2426
|
+
- Aliases (\`s-…\`, \`a-…\`, \`p-…\`, …) appear alongside UUIDs in
|
|
2422
2427
|
\`--verbose\` mode and replace UUIDs in default lean mode.
|
|
2423
2428
|
|
|
2424
2429
|
## Examples
|
|
@@ -2461,6 +2466,210 @@ ish study results --human
|
|
|
2461
2466
|
When you genuinely need multiple fields in one parse pass, \`--json\` is
|
|
2462
2467
|
still the right tool — \`--get\` is for single-value capture, not for
|
|
2463
2468
|
reshaping output.
|
|
2469
|
+
|
|
2470
|
+
## Slicing study results
|
|
2471
|
+
|
|
2472
|
+
\`ish study results <id>\` accepts filter flags (\`--frame\`, \`--segment\`,
|
|
2473
|
+
\`--turn\`, \`--side\`, \`--assignment\`, \`--step\`, \`--sentiment\`,
|
|
2474
|
+
\`--actor\`, \`--iteration\`, \`--participant\`) and projection flags
|
|
2475
|
+
(\`--group-by iteration|frame|segment|turn|assignment|step\`). When any
|
|
2476
|
+
filter is passed on the default \`study results\` envelope, the envelope
|
|
2477
|
+
gains a \`totals_unfiltered\` field (\`{participant_count,
|
|
2478
|
+
interaction_count}\`) so an agent can sanity-check coverage: "matched
|
|
2479
|
+
12 / 80 participants". A zero-match filter returns the stable envelope
|
|
2480
|
+
with \`participant_count: 0\` and exit code **0** (not 4) — slicing
|
|
2481
|
+
never errors on no-match. \`--group-by\` returns a different shape — a
|
|
2482
|
+
uniform envelope \`{axis, rows, totals_unfiltered, modality_warnings,
|
|
2483
|
+
study_id, modality}\` (see \`guides/slicing-results\`).
|
|
2484
|
+
|
|
2485
|
+
\`--group-by\` is **router-gated by modality**: \`frame\` requires
|
|
2486
|
+
interactive, \`segment\` requires media (video / audio / text / document),
|
|
2487
|
+
\`turn\` requires chat. Mismatched filter flags (e.g. \`--segment 0\` on
|
|
2488
|
+
an interactive study) emit a stderr warning and are ignored — they
|
|
2489
|
+
don't error. Full worked examples in \`guides/slicing-results\`.
|
|
2490
|
+
`;
|
|
2491
|
+
const GUIDE_SLICING_RESULTS = `# guide: slicing study results
|
|
2492
|
+
|
|
2493
|
+
\`ish study results <id>\` returns a kitchen-sink envelope by default
|
|
2494
|
+
(every participant, every interaction, every interview answer). For
|
|
2495
|
+
narrower questions — *"what differed on the login screen across these
|
|
2496
|
+
five iterations?"*, *"who failed verify-email, and why?"*, *"frustrated
|
|
2497
|
+
reactions to segment 3 of the video"* — \`ish study results\` accepts
|
|
2498
|
+
**filter flags** (which interactions to keep) and **projection flags**
|
|
2499
|
+
(how to roll up what survives). Filters compose with AND across flags
|
|
2500
|
+
and OR within \`--sentiment\`. Filters and projections are pure
|
|
2501
|
+
client-side; no extra round trip beyond the standard study fetch.
|
|
2502
|
+
|
|
2503
|
+
## Filter flags
|
|
2504
|
+
|
|
2505
|
+
| Flag | Matches | Where it applies |
|
|
2506
|
+
|-------------------------------|-----------------------------------------------------------------------------------------------|------------------------------------------------------------------|
|
|
2507
|
+
| \`--frame <ref>\` | Interactions whose Frame name contains \`<ref>\` (case-insensitive). Also accepts a full Frame UUID, an \`f-…\` alias, or a \`frame_version_id\` UUID. | interactive — warn + ignore on chat / media |
|
|
2508
|
+
| \`--segment <ref>\` | Integer matches \`actions[0].data.segment_index\`; non-integer is a substring match against \`segment_label\`. | video, audio, text, document — warn + ignore elsewhere |
|
|
2509
|
+
| \`--turn <n>\` | Interactions whose \`actions[0].data.turn_index == n\`. | chat (external_chatbot + participant_pair) |
|
|
2510
|
+
| \`--side <a\|b>\` | Interactions whose parent assignment has \`side == a\` or \`side == b\`. | chat participant_pair — warn + ignore on other chat / non-chat |
|
|
2511
|
+
| \`--assignment <ref>\` | Assignment UUID, or substring match against the assignment name. | all |
|
|
2512
|
+
| \`--step <ref>\` | Filters \`participant_assignments[].step_results[]\` to verdicts matching the step id or name. | interactive + external_chatbot chat (steps live there) |
|
|
2513
|
+
| \`--sentiment <labels>\` | Comma-separated, case-insensitive label list (repeatable). Drops null-sentiment rows. | all |
|
|
2514
|
+
| \`--actor <ai\|human\|user>\` | Restrict by actor. | all |
|
|
2515
|
+
| \`--iteration <ref>\` | Iteration UUID, iteration alias (\`i-…\`), or label (\`A\`, \`B\`, … case-insensitive). | all |
|
|
2516
|
+
| \`--participant <ref>\` | Participant UUID or \`pt-…\` alias. | all |
|
|
2517
|
+
| \`--include-unmatched\` | With \`--frame\`, keep degraded captures (\`frame_version_id: null\`) under a synthetic \`_unmatched\` bucket instead of dropping them. | interactive |
|
|
2518
|
+
| \`--include-evidence\` | With \`--step\`, also drop interactions not listed in any surviving \`step_results[].evidence_interaction_ids[]\`. | interactive + external_chatbot chat |
|
|
2519
|
+
|
|
2520
|
+
**Modality mismatch is not an error.** Pass \`--segment 0\` on an
|
|
2521
|
+
interactive study and the filter is ignored with a stderr warning.
|
|
2522
|
+
The exception is \`--group-by\` — see below.
|
|
2523
|
+
|
|
2524
|
+
## Projection flags (--group-by)
|
|
2525
|
+
|
|
2526
|
+
Every \`--group-by\` axis returns the same envelope:
|
|
2527
|
+
\`{axis, rows, totals_unfiltered, modality_warnings, study_id, modality}\`.
|
|
2528
|
+
Top-level \`axis\` echoes the requested axis; \`study_id\` is the \`s-…\`
|
|
2529
|
+
alias; \`modality\` echoes the study's modality. \`rows\` is an
|
|
2530
|
+
axis-specific array of slice objects (see the table below for the per-row
|
|
2531
|
+
shape). \`modality_warnings\` carries any filter-flag mismatches
|
|
2532
|
+
(e.g. \`--turn\` on a non-chat study); empty array when none.
|
|
2533
|
+
|
|
2534
|
+
| Axis | Row shape (one element of \`rows[]\`) | Modality |
|
|
2535
|
+
|-------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|
|
|
2536
|
+
| \`iteration\` | \`{iteration_id, iteration_label, participant_count, interaction_count, sentiment, sample_comments, top_actions}\` | all |
|
|
2537
|
+
| \`frame\` | \`{frame_id, frame_label, interaction_count, sentiment_histogram, sample_comments, participant_aliases}\` | interactive (router errors on non-interactive) |
|
|
2538
|
+
| \`segment\` | \`{segment_index, segment_label, interaction_count, sentiment_histogram, engagement_histogram, sample_comments}\` | media (router errors on non-media) |
|
|
2539
|
+
| \`turn\` | \`{turn_index, interaction_count, sentiment_histogram, sample_replies, failures}\` | chat (router errors on non-chat) |
|
|
2540
|
+
| \`assignment\` | \`{assignment_id, assignment_name, interaction_count, sentiment_histogram, step_completion}\` | all |
|
|
2541
|
+
| \`step\` | \`{assignment_id, assignment_name, step_id, step_name, total, passed, inconclusive, failed, rate, participant_verdicts: [{participant_alias, verdict, reason, evidence_interaction_ids}]}\` | interactive + external_chatbot chat |
|
|
2542
|
+
|
|
2543
|
+
\`--group-by\` is **mutually exclusive with \`--summary\` and
|
|
2544
|
+
\`--transcript\`**. \`--group-by frame\` on a chat study, \`--group-by
|
|
2545
|
+
turn\` on a video study, etc. error at the surface (exit 2) with a
|
|
2546
|
+
clear message before any IO. The error envelope includes a \`hint\`
|
|
2547
|
+
field naming the axis that DOES apply to the study's modality
|
|
2548
|
+
(\`use --group-by segment\` on audio/video/text/document, \`use --group-by
|
|
2549
|
+
turn\` on chat, \`use --group-by frame\` on interactive) — agents can
|
|
2550
|
+
branch on it to retry productively in one hop.
|
|
2551
|
+
|
|
2552
|
+
## The empty-slice contract
|
|
2553
|
+
|
|
2554
|
+
A filter combination that matches zero interactions returns the
|
|
2555
|
+
**uniform envelope** with:
|
|
2556
|
+
|
|
2557
|
+
- \`rows: []\`
|
|
2558
|
+
- \`totals_unfiltered: {participant_count: <N>, interaction_count: <M>}\` populated
|
|
2559
|
+
- \`axis\`, \`study_id\`, \`modality\` still populated
|
|
2560
|
+
- exit code **0** (not 4)
|
|
2561
|
+
|
|
2562
|
+
\`totals_unfiltered\` is the agent's sanity check: *"my filter matched
|
|
2563
|
+
0 of 80 participants — is the filter too tight, or did the run not
|
|
2564
|
+
produce data?"*. The shape never collapses to \`null\` or a different
|
|
2565
|
+
envelope; \`--get participant_count\` is always safe on the default
|
|
2566
|
+
(non-\`--group-by\`) envelope.
|
|
2567
|
+
|
|
2568
|
+
The default+filter envelope (no \`--group-by\`) also carries
|
|
2569
|
+
\`modality_warnings: string[]\` — any filter flags that were dropped as
|
|
2570
|
+
off-modality (e.g. \`--turn 1\` on an interactive study) appear here.
|
|
2571
|
+
Agents piping stderr to \`/dev/null\` get the same signal on stdout.
|
|
2572
|
+
|
|
2573
|
+
## Worked examples
|
|
2574
|
+
|
|
2575
|
+
\`\`\`bash
|
|
2576
|
+
# What differed on the login screen across the five iterations?
|
|
2577
|
+
ish study results s-b2c --frame login --group-by iteration
|
|
2578
|
+
|
|
2579
|
+
# Frustrated reactions to segment 3 of the video
|
|
2580
|
+
ish study results s-b2c --segment 3 --sentiment Frustrated
|
|
2581
|
+
|
|
2582
|
+
# Who failed the "verify email" step, and why?
|
|
2583
|
+
ish study results s-b2c --assignment "Sign up" --step verify-email --group-by step
|
|
2584
|
+
|
|
2585
|
+
# Chat participant_pair: only side A turn 4
|
|
2586
|
+
ish study results s-b2c --side a --turn 4
|
|
2587
|
+
|
|
2588
|
+
# Surface degraded captures (frame_version_id: null) under a "_unmatched" bucket:
|
|
2589
|
+
ish study results s-b2c --frame login --include-unmatched --group-by frame
|
|
2590
|
+
|
|
2591
|
+
# Narrow the lean summary to a slice:
|
|
2592
|
+
ish study results s-b2c --summary --frame checkout --json
|
|
2593
|
+
\`\`\`
|
|
2594
|
+
|
|
2595
|
+
## Combining filters
|
|
2596
|
+
|
|
2597
|
+
Filters compose with **AND across flags** and **OR within
|
|
2598
|
+
\`--sentiment\`**. \`--frame login --sentiment Frustrated,Confused\`
|
|
2599
|
+
means "interactions on the login frame whose sentiment is Frustrated
|
|
2600
|
+
OR Confused". \`--summary\` is orthogonal to filters and narrows the
|
|
2601
|
+
summary over the filtered set. \`--transcript\` is single-participant
|
|
2602
|
+
and **errors when any filter or \`--group-by\` is set** (exit 2).
|
|
2603
|
+
|
|
2604
|
+
## Defensive handling of nullable fields
|
|
2605
|
+
|
|
2606
|
+
- \`interaction.sentiment\` is nullable (chat failure stubs,
|
|
2607
|
+
pre-sentiment rows). Dropped **only** when \`--sentiment\` is set; kept
|
|
2608
|
+
by every other filter.
|
|
2609
|
+
- \`interaction.frame_version_id\` is nullable on interactive studies
|
|
2610
|
+
(degraded captures, ~12% on a failing iteration). Dropped by
|
|
2611
|
+
\`--frame\` unless \`--include-unmatched\` is passed; surfaced as a
|
|
2612
|
+
\`_unmatched\` bucket in \`--group-by frame\`.
|
|
2613
|
+
- Chat \`bot_reply.failure\` rows are kept in the default envelope,
|
|
2614
|
+
dropped by \`--sentiment\` (they have \`sentiment: null\`), kept by
|
|
2615
|
+
\`--actor\`, visible in \`--group-by turn\` under a \`failures\`
|
|
2616
|
+
counter.
|
|
2617
|
+
|
|
2618
|
+
## --frame resolution
|
|
2619
|
+
|
|
2620
|
+
\`--frame login\` walks the frame list returned by
|
|
2621
|
+
\`GET /studies/{id}/frames\` and matches **case-insensitive substring**
|
|
2622
|
+
against the frame name. Other accepted shapes:
|
|
2623
|
+
|
|
2624
|
+
- \`--frame 6ec…\` — full Frame UUID (exact match)
|
|
2625
|
+
- \`--frame f-6ec\` — short alias resolved via \`alias-store\`
|
|
2626
|
+
- \`--frame 7ec…\` — a \`frame_version_id\` UUID (matches only that version)
|
|
2627
|
+
|
|
2628
|
+
Ambiguous substring (matches >1 frame) errors with the candidate list:
|
|
2629
|
+
|
|
2630
|
+
\`\`\`
|
|
2631
|
+
ish study results s-b2c --frame log
|
|
2632
|
+
# Error: --frame "log" is ambiguous — matched 2 frames: Login, Logout.
|
|
2633
|
+
# Use a more specific substring, a full Frame UUID, or an \`f-…\` alias.
|
|
2634
|
+
\`\`\`
|
|
2635
|
+
|
|
2636
|
+
No match at all errors and lists the available frame names.
|
|
2637
|
+
|
|
2638
|
+
## Common --get paths on a sliced envelope
|
|
2639
|
+
|
|
2640
|
+
\`\`\`
|
|
2641
|
+
# Sanity-check coverage:
|
|
2642
|
+
--get axis
|
|
2643
|
+
--get study_id
|
|
2644
|
+
--get modality
|
|
2645
|
+
--get totals_unfiltered.participant_count
|
|
2646
|
+
--get totals_unfiltered.interaction_count
|
|
2647
|
+
--get modality_warnings
|
|
2648
|
+
|
|
2649
|
+
# Per-iteration projection rows:
|
|
2650
|
+
--get rows.iteration_label # one label per line
|
|
2651
|
+
--get rows.0.participant_count
|
|
2652
|
+
--get rows.0.sentiment
|
|
2653
|
+
|
|
2654
|
+
# Per-frame / per-segment / per-turn (rows[] is the axis array):
|
|
2655
|
+
--get rows.0.frame_label
|
|
2656
|
+
--get rows.0.segment_index
|
|
2657
|
+
--get rows.0.sentiment_histogram
|
|
2658
|
+
|
|
2659
|
+
# Per-step:
|
|
2660
|
+
--get rows.0.rate
|
|
2661
|
+
--get rows.0.participant_verdicts.verdict
|
|
2662
|
+
\`\`\`
|
|
2663
|
+
|
|
2664
|
+
## Related
|
|
2665
|
+
|
|
2666
|
+
- \`concepts/study\` — the parent artifact whose results are being sliced.
|
|
2667
|
+
- \`concepts/assignment\` — defines the steps that \`--step\` and
|
|
2668
|
+
\`--group-by step\` filter against.
|
|
2669
|
+
- \`reference/json-mode\` — display vs capture vs chain output rules
|
|
2670
|
+
(\`--get\`, \`--fields\`, exit codes).
|
|
2671
|
+
- \`reference/aliases\` — \`s-…\` for studies, \`pt-…\` for participants,
|
|
2672
|
+
\`f-…\` for frames. Any UUID-accepting flag also accepts the alias.
|
|
2464
2673
|
`;
|
|
2465
2674
|
const GUIDE_FIRST_STUDY = `# guide: your first study, end to end
|
|
2466
2675
|
|
|
@@ -2830,6 +3039,8 @@ free credits before re-dispatch.
|
|
|
2830
3039
|
estimate at preview time — the CLI prints the shape (\`N × … × 2\`)
|
|
2831
3040
|
instead of a number.
|
|
2832
3041
|
|
|
3042
|
+
**Naming note:** "tier" in ish means **billing** tier (FREE / STARTER / PRO / ENTERPRISE — a credit-budget knob). It is NOT a simulation-quality dial. Per-run simulation behaviour (model, timing, retries) is controlled via \`ish config\` — see \`ish config --help\`. \`docs search tier\` returns billing results by design.
|
|
3043
|
+
|
|
2833
3044
|
## Related
|
|
2834
3045
|
|
|
2835
3046
|
- \`reference/billing-limits\` — per-tier *entity* caps (max
|
|
@@ -3264,13 +3475,13 @@ Optional \`--max-turns <n>\` (default 12) caps the chat per participant.
|
|
|
3264
3475
|
|
|
3265
3476
|
Audience size is set at run time for **external_chatbot** chat
|
|
3266
3477
|
studies. Use \`--sample <N>\` to pick N random simulatable profiles,
|
|
3267
|
-
or \`--all\` for the full pool. \`--
|
|
3478
|
+
or \`--all\` for the full pool. \`--person <ids>\` is also supported
|
|
3268
3479
|
for explicit selection:
|
|
3269
3480
|
\`\`\`
|
|
3270
3481
|
ish study run stu-xyz --sample 5 --wait
|
|
3271
3482
|
\`\`\`
|
|
3272
3483
|
|
|
3273
|
-
> **Pair-mode is different.** \`--sample\` / \`--
|
|
3484
|
+
> **Pair-mode is different.** \`--sample\` / \`--person\` / demographic
|
|
3274
3485
|
> filters on \`study run\` are **refused** for participant_pair iterations
|
|
3275
3486
|
> — pair groups live on the iteration itself. Set them at
|
|
3276
3487
|
> iteration-create time via \`--group-a/-b\` (with 1×N broadcast)
|
|
@@ -3426,7 +3637,7 @@ Keys (all optional): \`occupation\`, \`min_age\`, \`max_age\`,
|
|
|
3426
3637
|
\`requires_captions\`, \`uses_screen_reader\`, \`prefers_reduced_motion\`,
|
|
3427
3638
|
\`prefers_high_contrast\`, \`has_any_accessibility_need\`. The five \`*_in\`
|
|
3428
3639
|
arrays accept snake_case spec values; the five accessibility filters are
|
|
3429
|
-
booleans. Combine \`--
|
|
3640
|
+
booleans. Combine \`--group-a\` / \`--group-b\` and \`--role-criteria-*\` on the same side
|
|
3430
3641
|
to make criteria validate an explicit list (mismatch blocks the run).
|
|
3431
3642
|
|
|
3432
3643
|
MECE notes for the list filters:
|
|
@@ -3812,7 +4023,7 @@ cap at 40 entries.
|
|
|
3812
4023
|
- \`concepts/person\` — what a person is; structured fields.
|
|
3813
4024
|
- \`concepts/source\` — interview transcripts / audio / PDF inputs
|
|
3814
4025
|
for the people-generation flow.
|
|
3815
|
-
- \`reference/aliases\` — \`
|
|
4026
|
+
- \`reference/aliases\` — \`p-…\` is the person alias prefix.
|
|
3816
4027
|
`;
|
|
3817
4028
|
const GUIDE_MCP_ADD = `# guide: wire ish into your AI clients (\`ish mcp add\`)
|
|
3818
4029
|
|
|
@@ -4053,6 +4264,12 @@ const PAGES = [
|
|
|
4053
4264
|
description: "Login → workspace → people → study → iteration → run → results.",
|
|
4054
4265
|
body: GUIDE_FIRST_STUDY,
|
|
4055
4266
|
},
|
|
4267
|
+
{
|
|
4268
|
+
slug: "guides/slicing-results",
|
|
4269
|
+
title: "guide: slicing study results by frame / segment / turn / sentiment",
|
|
4270
|
+
description: "Filter and project `ish study results` — --frame, --segment, --turn, --side, --assignment, --step, --sentiment, --actor, --iteration, --participant; --group-by iteration|frame|segment|turn|assignment|step; totals_unfiltered + empty-slice contract.",
|
|
4271
|
+
body: GUIDE_SLICING_RESULTS,
|
|
4272
|
+
},
|
|
4056
4273
|
{
|
|
4057
4274
|
slug: "guides/chat",
|
|
4058
4275
|
title: "guide: chat-modality studies",
|
package/dist/lib/output.d.ts
CHANGED
|
@@ -35,10 +35,16 @@ export declare function outputList(rows: unknown[], json: boolean): void;
|
|
|
35
35
|
/**
|
|
36
36
|
* Error with valid options — used for content_type and similar validation.
|
|
37
37
|
* Surfaces valid_options in JSON so agents can self-correct.
|
|
38
|
+
*
|
|
39
|
+
* Optional `hint` is the agent's *actionable next step* (e.g. for a wrong
|
|
40
|
+
* --group-by axis on the current modality, the axis that DOES apply). Distinct
|
|
41
|
+
* from `valid_options`, which describes where the supplied value WOULD be
|
|
42
|
+
* valid. Both serialize into the error envelope when present.
|
|
38
43
|
*/
|
|
39
44
|
export declare class ValidationError extends Error {
|
|
40
45
|
valid_options: string[];
|
|
41
|
-
|
|
46
|
+
hint?: string | undefined;
|
|
47
|
+
constructor(message: string, valid_options: string[], hint?: string | undefined);
|
|
42
48
|
}
|
|
43
49
|
export declare function outputError(err: unknown, json: boolean): void;
|
|
44
50
|
export declare function printTable(headers: string[], rows: string[][]): void;
|
|
@@ -48,6 +54,12 @@ export declare function formatWorkspaceDetail(workspace: Record<string, unknown>
|
|
|
48
54
|
export declare function formatSiteAccessStatus(summary: import("./site-access.js").SiteAccessSummary, json: boolean): void;
|
|
49
55
|
export declare function formatStudyList(studies: Record<string, unknown>[], json: boolean): void;
|
|
50
56
|
export declare function formatStudyDetail(study: Record<string, unknown>, json: boolean, options?: OutputOptions, participants?: ReadonlyArray<Record<string, unknown>>): void;
|
|
57
|
+
/**
|
|
58
|
+
* Stable JSON envelope for `study results`. Schema is fixed regardless of
|
|
59
|
+
* study state — fields default to `null`, `0`, or `[]` when nothing has run.
|
|
60
|
+
* Agents can rely on the keys always being present (M4).
|
|
61
|
+
*/
|
|
62
|
+
export declare function buildStudyResultsEnvelope(study: Record<string, unknown>, participants: ReadonlyArray<Record<string, unknown>>): Record<string, unknown>;
|
|
51
63
|
export declare function formatStudyResults(study: Record<string, unknown>, participants: ReadonlyArray<Record<string, unknown>>, json: boolean): void;
|
|
52
64
|
/**
|
|
53
65
|
* `study results --summary` projection. Drops interview_answers + per-participant
|
|
@@ -102,3 +114,14 @@ export declare function deriveWinnerConfidence(args: {
|
|
|
102
114
|
}): "low" | "medium" | "high";
|
|
103
115
|
export declare function formatAskResults(ask: Record<string, unknown>, json: boolean, roundFilter?: number): void;
|
|
104
116
|
export declare function formatConfigList(configs: Record<string, unknown>[], json: boolean): void;
|
|
117
|
+
export type StudyResultsGroupByKind = "iteration" | "frame" | "segment" | "turn" | "assignment" | "step";
|
|
118
|
+
/**
|
|
119
|
+
* Render a `--group-by <kind>` projection wrapped in the uniform
|
|
120
|
+
* `SliceResponse` envelope (`{ axis, rows, totals_unfiltered,
|
|
121
|
+
* modality_warnings, study_id, modality }`). JSON mode is a thin
|
|
122
|
+
* pass-through to jsonOutput with `preProjected: true` so the lean
|
|
123
|
+
* transform doesn't strip our stable empties. Human mode pulls slices
|
|
124
|
+
* out of `rows` and renders one section per slice plus a small ASCII
|
|
125
|
+
* sentiment histogram.
|
|
126
|
+
*/
|
|
127
|
+
export declare function formatStudyResultsGroupBy(projection: unknown, kind: StudyResultsGroupByKind, json: boolean): void;
|