@azure-id/orc 1.9.2 → 2.1.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/CHANGELOG.md +722 -0
- package/README-id.md +56 -42
- package/README.md +58 -41
- package/bin/build-agents.js +125 -29
- package/bin/clear-logs.js +620 -0
- package/bin/cli.js +1873 -180
- package/bin/fix.js +459 -0
- package/bin/gotcha-import.js +1081 -0
- package/bin/gotcha.js +1566 -0
- package/bin/graph-query.js +1 -1
- package/bin/graph.js +717 -717
- package/bin/habit.js +1538 -0
- package/bin/mockrun-catalog.js +284 -276
- package/bin/onboarding-content.js +2 -1
- package/bin/pricing.json +28 -21
- package/bin/run-undo.js +398 -0
- package/bin/trace-write.js +869 -0
- package/bin/verify-contracts.js +627 -100
- package/bin/verify-package.js +68 -10
- package/bin/webui/api.js +151 -6
- package/bin/webui/app.html +239 -232
- package/bin/webui/css/00-tokens.css +110 -92
- package/bin/webui/css/04-motion.css +87 -0
- package/bin/webui/css/06-responsive.css +203 -178
- package/bin/webui/css/panels/behaviour.css +205 -0
- package/bin/webui/css/panels/hookui.css +79 -0
- package/bin/webui/fixtures/behaviour.js +562 -0
- package/bin/webui/fixtures/extra.js +9 -9
- package/bin/webui/fixtures/flow.js +81 -81
- package/bin/webui/fixtures/hookui.js +506 -431
- package/bin/webui/fixtures/index.js +66 -3
- package/bin/webui/fixtures/knowledge.js +9 -3
- package/bin/webui/fixtures/maintenance.js +123 -42
- package/bin/webui/fixtures/rules.js +1007 -1002
- package/bin/webui/fixtures/settings.js +6 -7
- package/bin/webui/fixtures/stats.js +25 -6
- package/bin/webui/fixtures/wait.js +98 -97
- package/bin/webui/i18n/en/behaviour.json +156 -0
- package/bin/webui/i18n/en/hookui.json +290 -194
- package/bin/webui/i18n/en/maintenance.json +71 -52
- package/bin/webui/i18n/en/nav.json +25 -24
- package/bin/webui/i18n/en/settings.json +60 -60
- package/bin/webui/i18n/en/tour.json +37 -35
- package/bin/webui/i18n/id/behaviour.json +156 -0
- package/bin/webui/i18n/id/hookui.json +290 -194
- package/bin/webui/i18n/id/maintenance.json +71 -52
- package/bin/webui/i18n/id/nav.json +25 -24
- package/bin/webui/i18n/id/settings.json +60 -60
- package/bin/webui/i18n/id/tour.json +37 -35
- package/bin/webui/js/01-i18n.js +155 -154
- package/bin/webui/js/05-banners.js +181 -172
- package/bin/webui/js/06-edit.js +193 -183
- package/bin/webui/js/90-tour.js +498 -494
- package/bin/webui/js/91-shortcuts.js +126 -126
- package/bin/webui/js/99-boot.js +121 -118
- package/bin/webui/js/panels/behaviour.js +1087 -0
- package/bin/webui/js/panels/hookui.js +2196 -1691
- package/bin/webui/js/panels/maintenance.js +336 -235
- package/bin/webui/js/panels/settings.js +726 -719
- package/mock-run/INDEX.md +110 -107
- package/mock-run/extra-slots.md +1 -1
- package/mock-run/gotcha-import.md +118 -0
- package/mock-run/habits.md +129 -0
- package/mock-run/orc-aftermath.md +392 -392
- package/mock-run/orc-budget.md +29 -33
- package/mock-run/orc-cli.md +200 -200
- package/mock-run/orc-explain.md +86 -86
- package/mock-run/orc-extra.md +389 -392
- package/mock-run/orc-fix.md +87 -0
- package/mock-run/orc-pattern.md +112 -112
- package/mock-run/orc-quick.md +6 -1
- package/mock-run/orc.md +157 -157
- package/package.json +1 -1
- package/templates/agents/MODEL-MAPPING.md +37 -34
- package/templates/agents/orc-advisor-opus-5-xhigh.md +1 -7
- package/templates/agents/orc-analyze-mini-opus-5-med.md +1 -6
- package/templates/agents/orc-analyze-mini-sonnet-5-high.md +2 -5
- package/templates/agents/{orc-claude-writer-opus-4-8-high.md → orc-claude-writer-opus-5-low.md} +48 -53
- package/templates/agents/orc-context-combiner-opus-5-high.md +1 -11
- package/templates/agents/orc-executor-haiku-4-5.md +14 -6
- package/templates/agents/orc-executor-opus-4-7-high.md +14 -6
- package/templates/agents/orc-executor-opus-4-7-med.md +14 -6
- package/templates/agents/orc-executor-opus-4-8-high.md +14 -6
- package/templates/agents/orc-executor-opus-5-high.md +14 -6
- package/templates/agents/orc-executor-opus-5-low.md +14 -6
- package/templates/agents/orc-executor-opus-5-med.md +14 -6
- package/templates/agents/orc-executor-sonnet-4-6-high.md +14 -6
- package/templates/agents/orc-executor-sonnet-4-6-med.md +14 -6
- package/templates/agents/orc-executor-sonnet-5-high.md +15 -7
- package/templates/agents/orc-executor-sonnet-5-low.md +155 -0
- package/templates/agents/orc-executor-sonnet-5-med.md +155 -0
- package/templates/agents/orc-graph-noter-sonnet-4-6-med.md +1 -10
- package/templates/agents/orc-judge-opus-5-xhigh.md +5 -9
- package/templates/agents/orc-learn-writer-opus-5-low.md +1 -7
- package/templates/agents/orc-pattern-codifier-opus-5-med.md +1 -8
- package/templates/agents/orc-pattern-codifier-sonnet-5-high.md +58 -63
- package/templates/agents/orc-planner-mini-opus-5-med.md +1 -4
- package/templates/agents/orc-planner-mini-sonnet-5-high.md +2 -3
- package/templates/agents/orc-planner-opus-5-med.md +1 -4
- package/templates/agents/orc-recon-opus-5-low.md +1 -8
- package/templates/agents/orc-recon-sonnet-4-6-med.md +1 -8
- package/templates/agents/orc-retro-opus-5-med.md +6 -8
- package/templates/agents/orc-retro-sonnet-5-high.md +7 -8
- package/templates/agents/orc-reviewer-opus-5-low.md +96 -0
- package/templates/agents/orc-scout-opus-5-low.md +1 -6
- package/templates/agents/orc-scout-sonnet-4-6-high.md +35 -39
- package/templates/agents/orc-system-analyst-opus-5-high.md +1 -6
- package/templates/agents/orc-test-author-opus-5-med.md +4 -5
- package/templates/agents/orc-trace-writer-haiku-4-5.md +3 -7
- package/templates/agents/orc-verifier-opus-5-med.md +16 -8
- package/templates/agents/{orc-wiki-scanner-opus-4-8-high.md → orc-wiki-scanner-opus-5-low.md} +74 -79
- package/templates/agents/orc-wiki-scanner-sonnet-5-high.md +97 -106
- package/templates/commands/orc-analyze.md +13 -21
- package/templates/commands/orc-fast.md +10 -15
- package/templates/commands/orc-fix.md +18 -0
- package/templates/commands/orc-poly.md +12 -21
- package/templates/commands/orc-pr-driver.md +11 -30
- package/templates/commands/orc-pr-setup.md +10 -31
- package/templates/commands/orc-route.md +11 -41
- package/templates/commands/orc-test.md +5 -60
- package/templates/commands/orc-wiki.md +64 -64
- package/templates/hooks/README.md +109 -7
- package/templates/hooks/orc-session-hook.js +339 -0
- package/templates/hooks/orc-statusline-render.js +317 -23
- package/templates/hooks/orc-statusline.js +165 -50
- package/templates/hooks/orc-subagent-line.js +23 -5
- package/templates/hooks/orc-weather-fetch.js +123 -0
- package/templates/skills/_shared/README.md +9 -0
- package/templates/skills/_shared/code-graph.md +47 -55
- package/templates/skills/_shared/config-precedence.md +3 -1
- package/templates/skills/_shared/extra-dispatch.md +78 -93
- package/templates/skills/_shared/gotchas.md +248 -177
- package/templates/skills/_shared/habits.md +101 -0
- package/templates/skills/_shared/lane-contract.md +84 -0
- package/templates/skills/_shared/opus5-only.md +14 -14
- package/templates/skills/_shared/phases/README.md +142 -83
- package/templates/skills/_shared/phases/analyst-gates.md +10 -21
- package/templates/skills/_shared/phases/execution.md +8 -14
- package/templates/skills/_shared/phases/house-rules.md +27 -32
- package/templates/skills/_shared/phases/intake.md +127 -133
- package/templates/skills/_shared/phases/mock-example.md +46 -56
- package/templates/skills/_shared/phases/plan-handoff.md +91 -97
- package/templates/skills/_shared/phases/planning.md +7 -17
- package/templates/skills/_shared/phases/preflight.md +19 -42
- package/templates/skills/_shared/phases/review.md +24 -28
- package/templates/skills/_shared/phases/rules.md +18 -42
- package/templates/skills/_shared/phases/scoring.md +55 -65
- package/templates/skills/_shared/phases/security-checklist.md +46 -50
- package/templates/skills/_shared/phases/security.md +45 -55
- package/templates/skills/_shared/phases/ship.md +6 -15
- package/templates/skills/_shared/phases/stop-resume.md +2 -5
- package/templates/skills/_shared/phases/summary.md +73 -48
- package/templates/skills/_shared/phases/testgen.md +41 -51
- package/templates/skills/_shared/phases/trace-verbs.md +447 -0
- package/templates/skills/_shared/phases/trace.md +66 -297
- package/templates/skills/_shared/phases/verify.md +62 -70
- package/templates/skills/_shared/phases/wave-grouping.md +128 -133
- package/templates/skills/_shared/phases/wiki-consult.md +10 -6
- package/templates/skills/_shared/read-ladder.md +2 -55
- package/templates/skills/_shared/return-validation.md +17 -70
- package/templates/skills/_shared/review-slice.md +106 -0
- package/templates/skills/_shared/smoke-gate.md +46 -28
- package/templates/skills/_shared/wait.md +1 -0
- package/templates/skills/context-combiner/SKILL.md +15 -44
- package/templates/skills/orc/README.md +2 -2
- package/templates/skills/orc/SKILL.md +35 -63
- package/templates/skills/orc/config.md +25 -27
- package/templates/skills/orc/examples/full-run-mock.md +2 -1
- package/templates/skills/orc/references/effort-and-mode.md +17 -17
- package/templates/skills/orc/references/pattern-gate.md +89 -89
- package/templates/skills/orc/references/phases/intake.md +41 -47
- package/templates/skills/orc/references/phases/integration.md +13 -19
- package/templates/skills/orc/references/preflight-report.md +11 -12
- package/templates/skills/orc/references/ultra-mode.md +9 -7
- package/templates/skills/orc/schemas/checkpoint.md +122 -122
- package/templates/skills/orc/subskills/orc-execution/SKILL.md +27 -73
- package/templates/skills/orc/subskills/orc-execution/core.md +12 -99
- package/templates/skills/orc/subskills/orc-execution/subagent.md +14 -13
- package/templates/skills/orc/subskills/orc-review-verify/SKILL.md +12 -53
- package/templates/skills/orc/subskills/orc-review-verify/core.md +52 -135
- package/templates/skills/orc/subskills/orc-review-verify/subagent.md +7 -7
- package/templates/skills/orc/subskills/orc-testgen/SKILL.md +11 -22
- package/templates/skills/orc/subskills/orc-testgen/core.md +20 -59
- package/templates/skills/orc/subskills/orc-testgen/subagent.md +7 -7
- package/templates/skills/orc-advisor/SKILL.md +56 -60
- package/templates/skills/orc-analyze/SKILL.md +33 -67
- package/templates/skills/orc-analyze/schemas/report-audit.md +2 -1
- package/templates/skills/orc-analyze/schemas/report-prose.md +2 -1
- package/templates/skills/orc-analyze-mini/SKILL.md +35 -70
- package/templates/skills/orc-claude/SKILL.md +14 -14
- package/templates/skills/orc-claude/examples/claude-run-mock.md +65 -65
- package/templates/skills/orc-diy/README.md +31 -0
- package/templates/skills/orc-diy/SKILL.md +27 -78
- package/templates/skills/orc-diy/references/blocks/pattern.md +18 -18
- package/templates/skills/orc-fast/SKILL.md +49 -75
- package/templates/skills/orc-fix/SKILL.md +110 -0
- package/templates/skills/orc-judge/SKILL.md +77 -82
- package/templates/skills/orc-mini/SKILL.md +64 -112
- package/templates/skills/orc-mini/examples/mini-run-mock.md +4 -2
- package/templates/skills/orc-pattern/SKILL.md +27 -48
- package/templates/skills/orc-poly/SKILL.md +32 -61
- package/templates/skills/orc-pr-driver/SKILL.md +25 -51
- package/templates/skills/orc-pr-driver/references/green-gate.md +113 -105
- package/templates/skills/orc-pr-setup/SKILL.md +20 -45
- package/templates/skills/orc-quick/README.md +44 -3
- package/templates/skills/orc-quick/SKILL.md +77 -108
- package/templates/skills/orc-quick/references/dispatch-gate.md +18 -6
- package/templates/skills/orc-quick/references/gh-mode.md +50 -1
- package/templates/skills/orc-quick/references/look.md +3 -1
- package/templates/skills/orc-retro/SKILL.md +20 -19
- package/templates/skills/orc-retro/examples/retro-mock.md +17 -17
- package/templates/skills/orc-route/SKILL.md +25 -45
- package/templates/skills/orc-test/SKILL.md +16 -37
- package/templates/skills/orc-verify/SKILL.md +14 -32
- package/templates/skills/orc-wait/SKILL.md +156 -163
- package/templates/skills/orc-wiki/README.md +325 -325
- package/templates/skills/orc-wiki/SKILL.md +195 -195
- package/templates/skills/orc-wiki/examples/wiki-run-mock.md +37 -37
- package/templates/skills/orc-wiki/references/extra.md +2 -2
- package/templates/skills/orc-wiki/references/partial-refresh.md +276 -271
- package/templates/skills/orc-wiki/references/phases/phase-0.md +2 -7
- package/templates/skills/orc-wiki/references/phases/phase-1.md +1 -6
- package/templates/skills/orc-wiki/references/phases/phase-2.md +4 -9
- package/templates/skills/orc-wiki/references/phases/phase-3.md +1 -6
- package/templates/skills/orc-wiki/references/phases/phase-3c.md +4 -8
- package/templates/agents/orc-claude-writer-opus-5-med.md +0 -55
- package/templates/agents/orc-reviewer-opus-5-med.md +0 -60
- package/templates/agents/orc-wiki-scanner-opus-5-med.md +0 -81
|
@@ -772,3 +772,82 @@ button.hk-pick-row:hover {
|
|
|
772
772
|
.hk-boards {
|
|
773
773
|
margin-bottom: 4px;
|
|
774
774
|
}
|
|
775
|
+
|
|
776
|
+
/* v2.0.4 — the line head's options and the editor's new controls. All flex,
|
|
777
|
+
so each one wraps on a narrow screen by itself. */
|
|
778
|
+
.hk-line-opts-wrap {
|
|
779
|
+
display: flex;
|
|
780
|
+
align-items: center;
|
|
781
|
+
flex-wrap: wrap;
|
|
782
|
+
gap: 8px 14px;
|
|
783
|
+
}
|
|
784
|
+
.hk-input.hk-short {
|
|
785
|
+
width: 7em;
|
|
786
|
+
}
|
|
787
|
+
.hk-input.hk-char {
|
|
788
|
+
width: 3.5em;
|
|
789
|
+
text-align: center;
|
|
790
|
+
}
|
|
791
|
+
.hk-colour,
|
|
792
|
+
.hk-hex,
|
|
793
|
+
.hk-pair,
|
|
794
|
+
.hk-state-row {
|
|
795
|
+
display: flex;
|
|
796
|
+
align-items: center;
|
|
797
|
+
flex-wrap: wrap;
|
|
798
|
+
gap: 6px;
|
|
799
|
+
}
|
|
800
|
+
.hk-colour {
|
|
801
|
+
flex-direction: column;
|
|
802
|
+
align-items: flex-start;
|
|
803
|
+
}
|
|
804
|
+
.hk-hex-pick {
|
|
805
|
+
width: 32px;
|
|
806
|
+
height: 26px;
|
|
807
|
+
padding: 0;
|
|
808
|
+
border: 1px solid var(--line);
|
|
809
|
+
border-radius: 6px;
|
|
810
|
+
background: none;
|
|
811
|
+
cursor: pointer;
|
|
812
|
+
}
|
|
813
|
+
.hk-state-row {
|
|
814
|
+
margin: 4px 0;
|
|
815
|
+
}
|
|
816
|
+
.hk-state-name {
|
|
817
|
+
min-width: 8em;
|
|
818
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
819
|
+
font-size: 12px;
|
|
820
|
+
}
|
|
821
|
+
/* A case button's sample, under its name. */
|
|
822
|
+
.hk-pick-tip {
|
|
823
|
+
display: block;
|
|
824
|
+
font-size: 11px;
|
|
825
|
+
color: var(--text-dim);
|
|
826
|
+
}
|
|
827
|
+
/* The CLI's own refusal text for a staged change. */
|
|
828
|
+
.hk-stage-out {
|
|
829
|
+
margin: 0;
|
|
830
|
+
padding: 8px 10px;
|
|
831
|
+
white-space: pre-wrap;
|
|
832
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
833
|
+
font-size: 12px;
|
|
834
|
+
border: 1px solid var(--line);
|
|
835
|
+
border-radius: 6px;
|
|
836
|
+
background: var(--surface-2);
|
|
837
|
+
}
|
|
838
|
+
.hk-staged-tag {
|
|
839
|
+
color: var(--ok);
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
/* v2.0.4 — the redraw timer, under the advanced card. */
|
|
843
|
+
.hk-anim {
|
|
844
|
+
display: flex;
|
|
845
|
+
flex-direction: column;
|
|
846
|
+
gap: 6px;
|
|
847
|
+
margin-top: 10px;
|
|
848
|
+
padding-top: 10px;
|
|
849
|
+
border-top: 1px solid var(--line);
|
|
850
|
+
}
|
|
851
|
+
.hk-anim-head {
|
|
852
|
+
font-weight: 600;
|
|
853
|
+
}
|
|
@@ -0,0 +1,562 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* fixtures/behaviour.js — canned data for `orc ui --fixtures`.
|
|
3
|
+
The Behaviour panel (v2.0.0 W7): `orc habit show|log|points --json`,
|
|
4
|
+
`orc gotcha list|card|quality|list --candidates --json`.
|
|
5
|
+
|
|
6
|
+
THE RULE FOR EVERY FILE IN HERE: carry ONE OF EVERY STATE, including the
|
|
7
|
+
ugly ones. Here that is every habit state (observed · proposed · applied ·
|
|
8
|
+
declined · never-ask · stale · shadowed · never), every class (apply ·
|
|
9
|
+
suggest · never), every `habits` mode (off · observe · propose), every
|
|
10
|
+
`by=` value, every gotcha source and status, and the three empty answers
|
|
11
|
+
(no traces yet, below the review floor, a card with zero matches).
|
|
12
|
+
test/webui/fixtures.test.js counts them.
|
|
13
|
+
|
|
14
|
+
Shapes MUST match what `bin/cli.js --json` really emits — a drifted
|
|
15
|
+
fixture is worse than no fixture. */
|
|
16
|
+
|
|
17
|
+
const { PROJECT } = require("./shell.js");
|
|
18
|
+
|
|
19
|
+
const DAY = 86400000;
|
|
20
|
+
const NOW = Date.now();
|
|
21
|
+
const LOG_DIR = PROJECT + "/.claude/orc/logs";
|
|
22
|
+
const STATE_PATH = PROJECT + "/.claude/orc/habits-state.json";
|
|
23
|
+
const CACHE_PATH = PROJECT + "/.claude/orc/habits-cache.json";
|
|
24
|
+
const STATE_WORDS = ["observed", "proposed", "applied", "declined", "never-ask", "stale", "shadowed", "never"];
|
|
25
|
+
const BY_SET = ["user", "ledger", "learned", "config", "default"];
|
|
26
|
+
const RULE = { window: 30, max_age_days: 180, half_life_answers: 10, weights: { user: 1, override: 1, ledger: 1, learned: 0.25, preselected: 0.25 }, excluded_by: ["config", "default"], min_n: 5, lb: 0.55, z: 1.96, last_agree: 3, stale_overrides: 2, stale_of: 3, expiry_days: 90, cooldown_answers: 10, cooldown_days: 14 };
|
|
27
|
+
|
|
28
|
+
const NULL_COMMANDS = { accept: null, decline: null, never: null, forget: null, reset: null, manual: null };
|
|
29
|
+
// One row, every key `habit show --json` emits, in its order.
|
|
30
|
+
function row(o) {
|
|
31
|
+
const base = {
|
|
32
|
+
id: "H-000000",
|
|
33
|
+
qid: "",
|
|
34
|
+
lanes: [],
|
|
35
|
+
title: "",
|
|
36
|
+
class: "suggest",
|
|
37
|
+
effective_class: "suggest",
|
|
38
|
+
careful: null,
|
|
39
|
+
key: null,
|
|
40
|
+
bucket: {},
|
|
41
|
+
state: "observed",
|
|
42
|
+
why: null,
|
|
43
|
+
stale_reason: null,
|
|
44
|
+
stale_detail: null,
|
|
45
|
+
top: null,
|
|
46
|
+
top_label: null,
|
|
47
|
+
count: 0,
|
|
48
|
+
total: 0,
|
|
49
|
+
n: 0,
|
|
50
|
+
n_eff: 0,
|
|
51
|
+
p: 0,
|
|
52
|
+
lb: 0,
|
|
53
|
+
last_agree: false,
|
|
54
|
+
passes: false,
|
|
55
|
+
proposable: false,
|
|
56
|
+
option: null,
|
|
57
|
+
value: null,
|
|
58
|
+
decided_at: null,
|
|
59
|
+
last_used: null,
|
|
60
|
+
line: null,
|
|
61
|
+
rule: null,
|
|
62
|
+
undo: null,
|
|
63
|
+
options: [],
|
|
64
|
+
share: 0,
|
|
65
|
+
streak: [],
|
|
66
|
+
context: "",
|
|
67
|
+
effect: null,
|
|
68
|
+
commands: NULL_COMMANDS,
|
|
69
|
+
};
|
|
70
|
+
const r = Object.assign(base, o);
|
|
71
|
+
r.commands = Object.assign({}, NULL_COMMANDS, o.commands || {});
|
|
72
|
+
return r;
|
|
73
|
+
}
|
|
74
|
+
const ruleLine = (lb, n_eff, n) => `Wilson95 LB ${lb} (n_eff ${n_eff}, raw n ${n}) — proposes at ≥ 0.55 with n ≥ 5 and the last 3 agreeing`;
|
|
75
|
+
|
|
76
|
+
const ROWS = [
|
|
77
|
+
row({
|
|
78
|
+
id: "H-4c1a9e", qid: "quick.q3.offer.review", lanes: ["orc-quick"], title: "Code review before commit", careful: "review-first",
|
|
79
|
+
bucket: { kind: "feature" }, state: "proposed", why: "the rule passes — proposed once, at the end of a run",
|
|
80
|
+
top: "review-first", top_label: "review first", count: 9, total: 10, n: 10, n_eff: 7.82, p: 0.9, lb: 0.6, last_agree: true, passes: true, proposable: true,
|
|
81
|
+
line: 'You chose review first in 9 of your last 10 answers to "Code review before commit" (one "commit directly" on 14-09).',
|
|
82
|
+
rule: ruleLine(0.6, 7.82, 10),
|
|
83
|
+
options: [{ v: "review-first", label: "review first", n: 9 }, { v: "commit-direct", label: "commit directly", n: 1 }, { v: "stop", label: "stop", n: 0 }],
|
|
84
|
+
share: 0.9, streak: [1, 1, 0, 1, 1, 0.25, 1, 1, 1, 1], context: "kind=feature",
|
|
85
|
+
effect: "If you accept, ORC puts review first first and marks it → usual. The question is still asked.",
|
|
86
|
+
commands: { accept: "orc habit accept H-4c1a9e", decline: "orc habit decline H-4c1a9e", never: "orc habit decline H-4c1a9e --never" },
|
|
87
|
+
}),
|
|
88
|
+
row({
|
|
89
|
+
id: "H-7d20b3", qid: "orc.phase-2.pause", lanes: ["orc"], title: "How often the run pauses", class: "apply", effective_class: "apply", careful: "every-1", key: "batch_pause_every",
|
|
90
|
+
state: "stale", stale_reason: "override", stale_detail: { option: "every-2", overrides: 2, of: 3 },
|
|
91
|
+
why: "you chose pause every 2 waves 2 of the last 3 times instead of your usual pause every wave — paused, not flipped",
|
|
92
|
+
top: "every-1", top_label: "pause every wave", count: 7, total: 10, n: 10, n_eff: 7.1, p: 0.7, lb: 0.39, last_agree: false, option: "every-1", decided_at: NOW - 40 * DAY, last_used: NOW - 3 * DAY,
|
|
93
|
+
line: 'You chose pause every wave in 7 of your last 10 answers to "How often the run pauses" (3 other answers, the last "pause every 2 waves" on 25-09).',
|
|
94
|
+
rule: ruleLine(0.39, 7.1, 10), undo: "orc habit forget H-7d20b3",
|
|
95
|
+
options: [{ v: "every-1", label: "pause every wave", n: 7 }, { v: "every-2", label: "pause every 2 waves", n: 3 }],
|
|
96
|
+
share: 0.7, streak: [1, 1, 1, 1, 1, 1, 1, 0, 1, 0],
|
|
97
|
+
effect: "ORC paused this habit. The question is asked again until you decide.",
|
|
98
|
+
commands: { forget: "orc habit forget H-7d20b3" },
|
|
99
|
+
}),
|
|
100
|
+
row({
|
|
101
|
+
id: "H-a19f02", qid: "mini.phase-x.mock", lanes: ["orc-mini"], title: "Mocked runnable example", class: "apply", effective_class: "apply", key: "mock_example",
|
|
102
|
+
state: "applied", why: "answers mock_example at the learned rank",
|
|
103
|
+
top: "skip", top_label: "skip it", count: 12, total: 13, n: 13, n_eff: 9.4, p: 0.92, lb: 0.71, last_agree: true, passes: true, option: "skip", value: "off", decided_at: NOW - 21 * DAY, last_used: NOW - 1 * DAY,
|
|
104
|
+
line: 'You chose skip it in 12 of your last 13 answers to "Mocked runnable example" (one "build the example" on 02-09).',
|
|
105
|
+
rule: ruleLine(0.71, 9.4, 13), undo: "orc habit forget H-a19f02",
|
|
106
|
+
options: [{ v: "skip", label: "skip it", n: 12 }, { v: "build", label: "build the example", n: 1 }],
|
|
107
|
+
share: 0.923, streak: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
|
108
|
+
effect: "ORC answers mock_example with skip it at the learned rank. Your config file still wins.",
|
|
109
|
+
commands: { forget: "orc habit forget H-a19f02" },
|
|
110
|
+
}),
|
|
111
|
+
row({
|
|
112
|
+
id: "H-0b77c5", qid: "orc.phase-8.ship", lanes: ["orc"], title: "How the change ships", bucket: { branch: "feature" },
|
|
113
|
+
state: "applied", why: "marks open a PR as your usual; the question is still asked",
|
|
114
|
+
top: "pr", top_label: "open a PR", count: 10, total: 11, n: 11, n_eff: 8.2, p: 0.91, lb: 0.66, last_agree: true, passes: true, option: "pr", decided_at: NOW - 30 * DAY, last_used: NOW - 2 * DAY,
|
|
115
|
+
line: 'You chose open a PR in 10 of your last 11 answers to "How the change ships" (one "commit only" on 28-08).',
|
|
116
|
+
rule: ruleLine(0.66, 8.2, 11), undo: "orc habit forget H-0b77c5",
|
|
117
|
+
options: [{ v: "pr", label: "open a PR", n: 10 }, { v: "commit", label: "commit only", n: 1 }, { v: "leave", label: "leave it uncommitted", n: 0 }],
|
|
118
|
+
share: 0.909, streak: [1, 1, 1, 1, 0.25, 1, 1, 1, 1, 1], context: "branch=feature",
|
|
119
|
+
effect: "ORC puts open a PR first and marks it → usual. The question is still asked.",
|
|
120
|
+
commands: { forget: "orc habit forget H-0b77c5" },
|
|
121
|
+
}),
|
|
122
|
+
row({
|
|
123
|
+
id: "H-3e5d18", qid: "any.analysis.depth", lanes: ["orc", "orc-analyze"], title: "Analysis depth",
|
|
124
|
+
state: "observed", why: "3 full-weight answers — the rule needs 5",
|
|
125
|
+
top: "standard", top_label: "standard", count: 3, total: 4, n: 3, n_eff: 3.4, p: 0.75, lb: 0.3,
|
|
126
|
+
line: 'You chose standard in 3 of your last 4 answers to "Analysis depth" (one "deep" on 11-09).',
|
|
127
|
+
rule: ruleLine(0.3, 3.4, 3),
|
|
128
|
+
options: [{ v: "standard", label: "standard", n: 3 }, { v: "deep", label: "deep", n: 1 }],
|
|
129
|
+
share: 0.75, streak: [1, 0, 1, 1],
|
|
130
|
+
effect: "If you accept, ORC puts standard first and marks it → usual. The question is still asked.",
|
|
131
|
+
}),
|
|
132
|
+
row({
|
|
133
|
+
id: "H-92ab40", qid: "orc.intake.testgen", lanes: ["orc"], title: "Author test cases before ship", class: "apply", effective_class: "apply", careful: "author", key: "generate_tests",
|
|
134
|
+
state: "shadowed", why: "your config sets generate_tests: true — the file wins, so this habit is shown and inert (was: proposed)",
|
|
135
|
+
top: "author", top_label: "author tests", count: 8, total: 8, n: 8, n_eff: 6.9, p: 1, lb: 0.65, last_agree: true, passes: true,
|
|
136
|
+
line: 'You chose author tests in 8 of your last 8 answers to "Author test cases before ship".',
|
|
137
|
+
rule: ruleLine(0.65, 6.9, 8),
|
|
138
|
+
options: [{ v: "author", label: "author tests", n: 8 }, { v: "skip", label: "skip tests", n: 0 }],
|
|
139
|
+
share: 1, streak: [1, 1, 1, 1, 1, 1, 1, 1],
|
|
140
|
+
effect: "If you accept, ORC answers generate_tests with author tests at the learned rank. Your config file still wins.",
|
|
141
|
+
}),
|
|
142
|
+
row({
|
|
143
|
+
id: "H-5f6e21", qid: "orc.phase-1.planner", lanes: ["orc"], title: "Which planner writes the plan",
|
|
144
|
+
state: "declined", why: "declined — it can come back after 10 more answers (4 so far) and 14 days (6 so far)",
|
|
145
|
+
top: "planner", top_label: "ORC planner", count: 8, total: 9, n: 9, n_eff: 7, p: 0.89, lb: 0.58, last_agree: true, passes: true, decided_at: NOW - 6 * DAY,
|
|
146
|
+
line: 'You chose ORC planner in 8 of your last 9 answers to "Which planner writes the plan" (one "Superpowers" on 03-09).',
|
|
147
|
+
rule: ruleLine(0.58, 7, 9), undo: "orc habit forget H-5f6e21",
|
|
148
|
+
options: [{ v: "planner", label: "ORC planner", n: 8 }, { v: "superpowers", label: "Superpowers", n: 1 }],
|
|
149
|
+
share: 0.889, streak: [1, 1, 0, 1, 1, 1, 1, 1, 1],
|
|
150
|
+
effect: "If you accept, ORC puts ORC planner first and marks it → usual. The question is still asked.",
|
|
151
|
+
commands: { reset: "orc habit reset H-5f6e21" },
|
|
152
|
+
}),
|
|
153
|
+
row({
|
|
154
|
+
id: "H-c40d9a", qid: "fast.f0.stale-wiki", lanes: ["orc-fast"], title: "A stale wiki at preflight",
|
|
155
|
+
state: "never-ask", why: "you said never — still observed, never proposed",
|
|
156
|
+
top: "refresh", top_label: "refresh the wiki", count: 6, total: 7, n: 7, n_eff: 5.8, p: 0.86, lb: 0.56, last_agree: true, passes: true, decided_at: NOW - 12 * DAY,
|
|
157
|
+
line: 'You chose refresh the wiki in 6 of your last 7 answers to "A stale wiki at preflight" (one "fall back to /orc-mini" on 01-09).',
|
|
158
|
+
rule: ruleLine(0.56, 5.8, 7), undo: "orc habit forget H-c40d9a",
|
|
159
|
+
options: [{ v: "refresh", label: "refresh the wiki", n: 6 }, { v: "mini", label: "fall back to /orc-mini", n: 1 }],
|
|
160
|
+
share: 0.857, streak: [1, 1, 1, 0, 1, 1, 1],
|
|
161
|
+
effect: "If you accept, ORC puts refresh the wiki first and marks it → usual. The question is still asked.",
|
|
162
|
+
commands: { reset: "orc habit reset H-c40d9a" },
|
|
163
|
+
}),
|
|
164
|
+
row({
|
|
165
|
+
id: "H-e81f63", qid: "orc.phase-5-5.security", lanes: ["orc", "orc-diy"], title: "Security review", class: "apply", effective_class: "never", careful: "run", key: "security_review",
|
|
166
|
+
state: "never", why: "your usual answer (skip it) is away from the careful side, so it is never applied — toward `on` only — a habit to skip security is never applied",
|
|
167
|
+
top: "skip", top_label: "skip it", count: 9, total: 10, n: 10, n_eff: 7.6, p: 0.9, lb: 0.6, last_agree: true, passes: true,
|
|
168
|
+
line: 'You chose skip it in 9 of your last 10 answers to "Security review" (one "run the security pass" on 09-09).',
|
|
169
|
+
rule: ruleLine(0.6, 7.6, 10),
|
|
170
|
+
options: [{ v: "skip", label: "skip it", n: 9 }, { v: "run", label: "run the security pass", n: 1 }],
|
|
171
|
+
share: 0.9, streak: [1, 1, 1, 0, 1, 1, 1, 1, 1, 1],
|
|
172
|
+
effect: "ORC shows this and never proposes it: toward `on` only — a habit to skip security is never applied.",
|
|
173
|
+
commands: { manual: "orc config set security_review off" },
|
|
174
|
+
}),
|
|
175
|
+
row({
|
|
176
|
+
id: "H-18aa7f", qid: "orc.phase-2.execution", lanes: ["orc"], title: "How the waves execute", effective_class: "never",
|
|
177
|
+
state: "never", why: "the habit only orders the offer",
|
|
178
|
+
top: "other", top_label: "other", count: 5, total: 8, n: 8, n_eff: 6, p: 0.63, lb: 0.31,
|
|
179
|
+
line: 'You chose other in 5 of your last 8 answers to "How the waves execute" (3 other answers, the last "parallel" on 20-09).',
|
|
180
|
+
rule: ruleLine(0.31, 6, 8),
|
|
181
|
+
options: [{ v: "other", label: "other", n: 5 }, { v: "parallel", label: "parallel", n: 3 }],
|
|
182
|
+
share: 0.625, streak: [0, 1, 1, 0, 1, 1, 0, 1],
|
|
183
|
+
effect: "ORC shows this and never proposes it: the habit only orders the offer.",
|
|
184
|
+
}),
|
|
185
|
+
];
|
|
186
|
+
|
|
187
|
+
function countsOf(rows) {
|
|
188
|
+
const c = {};
|
|
189
|
+
for (const s of STATE_WORDS) c[s] = rows.filter((r) => r.state === s).length;
|
|
190
|
+
return c;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// The heat map: weekday (Mon first) × hour. Deterministic, work-hours heavy.
|
|
194
|
+
function heatMap(scale) {
|
|
195
|
+
const out = [];
|
|
196
|
+
for (let d = 0; d < 7; d++) {
|
|
197
|
+
const r = [];
|
|
198
|
+
for (let h = 0; h < 24; h++) {
|
|
199
|
+
const work = d < 5 && h >= 9 && h <= 18 ? 1 : 0;
|
|
200
|
+
const v = work ? ((d * 7 + h * 3) % 5) + (h === 14 ? 3 : 0) : d >= 5 && h === 11 ? 1 : 0;
|
|
201
|
+
r.push(Math.round(v * scale));
|
|
202
|
+
}
|
|
203
|
+
out.push(r);
|
|
204
|
+
}
|
|
205
|
+
return out;
|
|
206
|
+
}
|
|
207
|
+
const WEEKS = Array.from({ length: 12 }, (_, i) => new Date(NOW - (12 - i) * 7 * DAY).toISOString().slice(0, 10));
|
|
208
|
+
const HOW = [
|
|
209
|
+
[30, 4, 0, 2, 1], [28, 5, 0, 2, 1], [27, 6, 1, 3, 0], [25, 6, 2, 3, 1], [24, 7, 3, 3, 0], [22, 8, 4, 3, 1],
|
|
210
|
+
[20, 8, 5, 4, 1], [19, 9, 6, 4, 0], [17, 9, 7, 4, 1], [16, 10, 8, 5, 1], [15, 10, 9, 5, 0], [14, 11, 9, 5, 1],
|
|
211
|
+
].map((w) => Object.fromEntries(BY_SET.map((b, i) => [b, w[i]])));
|
|
212
|
+
|
|
213
|
+
function show(mode, rows) {
|
|
214
|
+
const heat = heatMap(1);
|
|
215
|
+
return {
|
|
216
|
+
ok: true,
|
|
217
|
+
mode,
|
|
218
|
+
lane: null,
|
|
219
|
+
window: "90d",
|
|
220
|
+
log_dir: LOG_DIR,
|
|
221
|
+
state_path: STATE_PATH,
|
|
222
|
+
cache_path: CACHE_PATH,
|
|
223
|
+
traces: 94,
|
|
224
|
+
answers: 412,
|
|
225
|
+
excluded_runs: [{ run: "run-orc-pr-review-120926-101500.txt", reason: "untrusted_context" }],
|
|
226
|
+
count: rows.length,
|
|
227
|
+
rows,
|
|
228
|
+
tiles: { runs: 94, answers: 412, saved: 57, saved_prev: 36, qpr: 3.9, qpr_prev: 6.8 },
|
|
229
|
+
rhythm: {
|
|
230
|
+
days: Array.from({ length: 14 }, (_, i) => ({ date: new Date(NOW - (13 - i) * DAY).toISOString().slice(0, 10), answers: [4, 6, 0, 0, 9, 7, 5, 8, 3, 0, 0, 6, 7, 5][i] })),
|
|
231
|
+
heat,
|
|
232
|
+
lanes: [{ lane: "orc-quick", n: 38 }, { lane: "orc-mini", n: 22 }, { lane: "orc", n: 17 }, { lane: "orc-fast", n: 9 }, { lane: "orc-analyze", n: 5 }, { lane: "orc-diy", n: 3 }],
|
|
233
|
+
weeks: WEEKS,
|
|
234
|
+
qpr: [6.8, 6.5, 6.1, 5.9, null, 5.2, 4.9, 4.6, 4.4, 4.2, 4.0, 3.9],
|
|
235
|
+
how: HOW,
|
|
236
|
+
by: BY_SET,
|
|
237
|
+
},
|
|
238
|
+
portrait: [
|
|
239
|
+
{ k: "lanes", line: "You run most work through orc-quick (40% of 94 runs)." },
|
|
240
|
+
{ k: "time", line: "Your busiest hour is Tue 14:00 (7 runs)." },
|
|
241
|
+
{ k: "questions", line: "You answered 3.9 questions per run, against 6.8 in the window before." },
|
|
242
|
+
{ k: "usual", line: "Mocked runnable example: usually skip it (12 of 13)." },
|
|
243
|
+
].concat(mode === "propose" ? [{ k: "proposal", line: "1 habit is ready for your decision." }] : []),
|
|
244
|
+
proposal:
|
|
245
|
+
mode === "propose" && rows.length
|
|
246
|
+
? { id: "H-4c1a9e", qid: "quick.q3.offer.review", kind: "propose", option: "review-first", line: ROWS[0].line + " Make it your usual? [yes · not now · never]", yes: "orc habit accept H-4c1a9e", keep: null, later: "orc habit decline H-4c1a9e", never: "orc habit decline H-4c1a9e --never", trace: "ASK habit.proposal :: offered=yes|later|never rec=none chose=<yes|later|never> by=user" }
|
|
247
|
+
: null,
|
|
248
|
+
state_words: STATE_WORDS,
|
|
249
|
+
rule: RULE,
|
|
250
|
+
modes: ["off", "observe", "propose"],
|
|
251
|
+
classes: ["apply", "suggest", "never"],
|
|
252
|
+
counts: countsOf(rows),
|
|
253
|
+
next_run: [
|
|
254
|
+
{ lane: "orc", id: "H-0b77c5", qid: "orc.phase-8.ship", line: '"How the change ships" offers open a PR first, marked → usual (H-0b77c5)' },
|
|
255
|
+
{ lane: "orc-mini", id: "H-a19f02", qid: "mini.phase-x.mock", line: "mock_example: off — learned (H-a19f02)" },
|
|
256
|
+
],
|
|
257
|
+
files: [LOG_DIR + "/*.txt", STATE_PATH],
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// `habits: propose` — every state, with the proposal.
|
|
262
|
+
const habitsPropose = show("propose", ROWS);
|
|
263
|
+
// `habits: observe` — the tabs fill, and NOTHING is proposed: the row the rule
|
|
264
|
+
// passes for stays `observed` (the CLI's "`habits: observe` never proposes").
|
|
265
|
+
const habitsObserve = show(
|
|
266
|
+
"observe",
|
|
267
|
+
ROWS.map((r) =>
|
|
268
|
+
r.commands.accept
|
|
269
|
+
? Object.assign({}, r, { state: "observed", why: "the rule passes — `habits: observe` never proposes", commands: NULL_COMMANDS })
|
|
270
|
+
: r
|
|
271
|
+
)
|
|
272
|
+
);
|
|
273
|
+
// `habits: off` — exit 3. It reads only the cache an earlier on-period left.
|
|
274
|
+
const habitsOff = {
|
|
275
|
+
ok: false,
|
|
276
|
+
reason: "off",
|
|
277
|
+
message: "habits is off. Turn it on with: orc config set habits observe (or propose). Nothing is ever applied without your yes.",
|
|
278
|
+
mode: "off",
|
|
279
|
+
modes: ["off", "observe", "propose"],
|
|
280
|
+
kept: 212,
|
|
281
|
+
on: ["orc config set habits observe", "orc config set habits propose"],
|
|
282
|
+
};
|
|
283
|
+
// Exit 1 — no ASK lines yet in this window.
|
|
284
|
+
const habitsEmpty = Object.assign(show("propose", []), {
|
|
285
|
+
window: "30d",
|
|
286
|
+
traces: 0,
|
|
287
|
+
answers: 0,
|
|
288
|
+
excluded_runs: [],
|
|
289
|
+
tiles: { runs: 0, answers: 0, saved: 0, saved_prev: 0, qpr: null, qpr_prev: null },
|
|
290
|
+
portrait: [],
|
|
291
|
+
proposal: null,
|
|
292
|
+
next_run: [],
|
|
293
|
+
});
|
|
294
|
+
habitsEmpty.rhythm = Object.assign({}, habitsEmpty.rhythm, {
|
|
295
|
+
heat: heatMap(0),
|
|
296
|
+
lanes: [],
|
|
297
|
+
qpr: Array(12).fill(null),
|
|
298
|
+
how: Array.from({ length: 12 }, () => Object.fromEntries(BY_SET.map((b) => [b, 0]))),
|
|
299
|
+
days: habitsEmpty.rhythm.days.map((d) => ({ date: d.date, answers: 0 })),
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
// `orc habit log --json --limit 40` — every by= value.
|
|
303
|
+
const LOG_ROWS = [
|
|
304
|
+
["quick.q3.offer.review", "orc-quick", "review-first", "user", "review-first"],
|
|
305
|
+
["mini.phase-x.mock", "orc-mini", "skip", "learned", "skip"],
|
|
306
|
+
["orc.phase-8.ship", "orc", "pr", "user", "pr"],
|
|
307
|
+
["orc.intake.testgen", "orc", "author", "config", null],
|
|
308
|
+
["orc.phase-5-5.security", "orc", "skip", "user", null],
|
|
309
|
+
["any.analysis.depth", "orc-analyze", "standard", "ledger", null],
|
|
310
|
+
["orc.phase-2.pause", "orc", "every-2", "user", "every-1"],
|
|
311
|
+
["any.stop.where", "orc-mini", "here", "default", null],
|
|
312
|
+
["quick.q3.offer.tests", "orc-quick", "update", "user", null],
|
|
313
|
+
["orc.phase-1.planner", "orc", "planner", "user", null],
|
|
314
|
+
];
|
|
315
|
+
const habitLog = {
|
|
316
|
+
ok: true,
|
|
317
|
+
count: LOG_ROWS.length,
|
|
318
|
+
total: 412,
|
|
319
|
+
events: LOG_ROWS.map(([qid, lane, chose, by, pre], i) => ({
|
|
320
|
+
id: "H-" + (0x1a2b3c + i * 977).toString(16).slice(0, 6),
|
|
321
|
+
run: `run-${lane}-fixture-${i}.txt`,
|
|
322
|
+
lane,
|
|
323
|
+
at: NOW - (i * 3 + 1) * 3600000,
|
|
324
|
+
qid,
|
|
325
|
+
offered: [chose, "other"],
|
|
326
|
+
rec: pre || "none",
|
|
327
|
+
chose,
|
|
328
|
+
by,
|
|
329
|
+
pre,
|
|
330
|
+
ctx: {},
|
|
331
|
+
})),
|
|
332
|
+
};
|
|
333
|
+
const habitLogEmpty = { ok: true, count: 0, total: 0, events: [] };
|
|
334
|
+
|
|
335
|
+
// `orc habit log --states --json` — every `by` a change can carry.
|
|
336
|
+
const habitStates = {
|
|
337
|
+
ok: true,
|
|
338
|
+
count: 5,
|
|
339
|
+
history: [
|
|
340
|
+
{ id: "H-7d20b3", from: "applied", to: "stale", by: "system", at: NOW - 3 * DAY, reason: "2 overrides in the last 3", inverse: null },
|
|
341
|
+
{ id: "H-5f6e21", from: "proposed", to: "declined", by: "panel", at: NOW - 6 * DAY, reason: "not now", inverse: "orc habit reset H-5f6e21" },
|
|
342
|
+
{ id: "H-c40d9a", from: "proposed", to: "never-ask", by: "lane", at: NOW - 12 * DAY, reason: "never ask", inverse: "orc habit reset H-c40d9a" },
|
|
343
|
+
{ id: "H-a19f02", from: "proposed", to: "applied", by: "user", at: NOW - 21 * DAY, reason: "usual: skip (12 of 13)", inverse: "orc habit forget H-a19f02" },
|
|
344
|
+
{ id: "H-0b77c5", from: "proposed", to: "applied", by: "lane", at: NOW - 30 * DAY, reason: "usual: pr (10 of 11)", inverse: "orc habit forget H-0b77c5" },
|
|
345
|
+
],
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
// `orc habit points --json` — a slice of the registry (the shape, not all 30).
|
|
349
|
+
const habitPoints = {
|
|
350
|
+
ok: true,
|
|
351
|
+
count: 2,
|
|
352
|
+
points: [
|
|
353
|
+
{ qid: "mini.phase-x.mock", lanes: ["orc-mini"], phase: "phase-x", file: "orc-mini/SKILL.md", title: "Mocked runnable example", options: { build: "build the example", skip: "skip it" }, class: "apply", careful: null, key: "mock_example", values: { build: "on", skip: "off" }, ctx: [], why: "a mock example has no careful side, so both answers can be learned" },
|
|
354
|
+
{ qid: "quick.q3.offer.review", lanes: ["orc-quick"], phase: "q3", file: "orc-quick/SKILL.md", title: "Code review before commit", options: { "review-first": "review first", "commit-direct": "commit directly", stop: "stop" }, class: "suggest", careful: "review-first", key: null, ctx: ["kind", "branch"], why: "a review is a dispatch, so its gate is still asked — the habit only orders the offer" },
|
|
355
|
+
],
|
|
356
|
+
meta_qids: ["habit.proposal"],
|
|
357
|
+
classes: ["apply", "suggest", "never"],
|
|
358
|
+
rule: RULE,
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
// ── Gotchas ─────────────────────────────────────────────────────────────────
|
|
362
|
+
// The EXTRA ledger entries (G-004 …) that, with Knowledge's three, carry every
|
|
363
|
+
// source and every status. knowledge.js appends them to `gotchas`.
|
|
364
|
+
const SOURCES = ["repair", "drift", "review", "verify", "defect", "pr", "sonar", "sarif", "ci", "dismissal"];
|
|
365
|
+
const KIND_OF = { repair: "repair", drift: "drift", review: "review", verify: "verify", defect: "repair", ci: "repair", pr: "review", sonar: "review", sarif: "review", dismissal: "review" };
|
|
366
|
+
const EXTRA = [
|
|
367
|
+
["G-004", "orders", "drift", { rule: null, scope: "src/orders/**/*.ts", symptom: "the schema and the client disagree on totalCents", fix: "regenerate the client after a schema change", origin: "run-orc-orders-100926-091200 · drift" }, "active", [0, 1, 0, 2, 1, 0, 1]],
|
|
368
|
+
["G-005", "billing", "defect", { rule: "repro red→green", scope: "src/billing/**", symptom: "a refund is booked twice on retry", fix: "key the refund on the idempotency key", origin: "issue 88 · 03-09-2026" }, "active", [0, 0, 1, 0, 0, 2, 1]],
|
|
369
|
+
["G-006", "api", "pr", { rule: "PR 142 · thread 3", scope: "src/routes/**/*.js", symptom: "a handler returns 200 on a validation error", fix: "return 422 with the field name", origin: "PR 142 · thread 3 · 08-09-2026" }, "active", [1, 0, 2, 1, 0, 1, 3]],
|
|
370
|
+
["G-007", "client", "sonar", { rule: "typescript:S1854", scope: "client/src/**/*.vue", symptom: "a dead store in a computed property", fix: "remove the unused assignment", origin: "sonar · 11-09-2026" }, "active", [2, 1, 1, 0, 2, 1, 1]],
|
|
371
|
+
["G-008", "infra", "sarif", { rule: "js/path-injection", scope: "src/export/**", symptom: "a file path built from a query string", fix: "resolve under the export root and refuse ..", origin: "sarif codeql.sarif · 12-09-2026" }, "active", [0, 0, 0, 1, 0, 1, 0]],
|
|
372
|
+
["G-009", "build", "ci", { rule: "ci: lint", scope: "src/**/*.ts", symptom: "CI lint fails on an unused import", fix: "run the linter before you push", origin: "CI run 5521 · 15-09-2026" }, "quiet", [0, 0, 0, 0, 0, 0, 0]],
|
|
373
|
+
["G-010", "i18n", "dismissal", { rule: null, scope: "client/src/i18n/**", symptom: "long translation files flagged as too long", fix: "(do not flag)", origin: "dismissal · 18-09-2026", polarity: "suppress" }, "active", [0, 1, 0, 1, 1, 0, 1]],
|
|
374
|
+
["G-011", "legacy", "repair", { rule: null, scope: "src/legacy-session/**", symptom: "the old session cookie is read twice", fix: "read it once in the middleware", origin: "run-orc-auth-020826-100000 · repair" }, "orphaned", [0, 0, 0, 0, 0, 0, 0]],
|
|
375
|
+
];
|
|
376
|
+
const gotchaExtraEntries = EXTRA.map(([id, area, source, f]) => ({
|
|
377
|
+
id,
|
|
378
|
+
area,
|
|
379
|
+
kind: KIND_OF[source],
|
|
380
|
+
hits: 3,
|
|
381
|
+
last_seen: "20-09-2026",
|
|
382
|
+
trigger: f.symptom,
|
|
383
|
+
fields: Object.assign({ trigger: f.symptom, symptom: f.symptom, cause: "(see origin)", fix: f.fix, scope: f.scope, origin: f.origin, hits: "3", last_seen: "20-09-2026", source }, f.rule ? { rule: f.rule } : {}, f.polarity ? { polarity: f.polarity } : {}),
|
|
384
|
+
}));
|
|
385
|
+
// The panel view `orc gotcha list --json` carries as `panel`, for G-001 … G-011.
|
|
386
|
+
const BASE_ROWS = [
|
|
387
|
+
{ id: "G-001", source: "repair", status: "active", status_reason: null, rule: null, scope: "tests/**/*.test.js", fix: "close the http server in afterAll and await it", symptom: "`npm test` never exits; CI times out at 10 minutes", polarity: "flag", origin: "run-orc-add-billing-050826-141233 · TDD repair round 2", weeks: [1, 0, 2, 1, 0, 1, 2] },
|
|
388
|
+
{ id: "G-002", source: "review", status: "active", status_reason: null, rule: null, scope: "client/src/**/*.tsx", fix: "use parseInZone from src/time/zone.ts", symptom: "bookings land one day early for users west of UTC", polarity: "flag", origin: "run-orc-bookings-220726-093000 · review", weeks: [0, 0, 1, 0, 0, 1, 0] },
|
|
389
|
+
{ id: "G-003", source: "verify", status: "quiet", status_reason: null, rule: null, scope: ".github/workflows/**", fix: "set NODE_OPTIONS in the workflow, not in package.json", symptom: "the CI build is OOM-killed with no error line", polarity: "flag", origin: "run-orc-ci-140626-110000 · verify", weeks: [0, 0, 0, 0, 0, 0, 0] },
|
|
390
|
+
];
|
|
391
|
+
const panelRows = BASE_ROWS.concat(
|
|
392
|
+
EXTRA.map(([id, , source, f, status, weeks]) => ({
|
|
393
|
+
id,
|
|
394
|
+
source,
|
|
395
|
+
status,
|
|
396
|
+
status_reason: status === "orphaned" ? "its scope matches no tracked file" : null,
|
|
397
|
+
rule: f.rule || null,
|
|
398
|
+
scope: f.scope,
|
|
399
|
+
fix: f.fix,
|
|
400
|
+
symptom: f.symptom,
|
|
401
|
+
polarity: f.polarity || "flag",
|
|
402
|
+
origin: f.origin,
|
|
403
|
+
weeks,
|
|
404
|
+
}))
|
|
405
|
+
);
|
|
406
|
+
const bySource = {};
|
|
407
|
+
for (const r of panelRows) bySource[r.source] = (bySource[r.source] || 0) + 1;
|
|
408
|
+
const gotchaPanel = {
|
|
409
|
+
sources: SOURCES,
|
|
410
|
+
statuses: ["active", "candidate", "quiet", "orphaned"],
|
|
411
|
+
by_source: SOURCES.filter((s) => bySource[s]).map((s) => ({ source: s, n: bySource[s] })),
|
|
412
|
+
status_counts: { active: panelRows.filter((r) => r.status === "active").length, candidate: 1, quiet: 2, orphaned: 1 },
|
|
413
|
+
rows: panelRows,
|
|
414
|
+
sync: {
|
|
415
|
+
last_sync: new Date(NOW - 2 * 3600000).toISOString(),
|
|
416
|
+
sources: [
|
|
417
|
+
{ name: "sonar", state: "ok", last_ok: new Date(NOW - 2 * 3600000).toISOString(), last_error: null },
|
|
418
|
+
{ name: "pr", state: "ok", last_ok: new Date(NOW - 2 * 3600000).toISOString(), last_error: null },
|
|
419
|
+
{ name: "ci", state: "timed out", last_ok: new Date(NOW - 3 * DAY).toISOString(), last_error: "ci timed out" },
|
|
420
|
+
{ name: "defects", state: "not configured", last_ok: null, last_error: null },
|
|
421
|
+
],
|
|
422
|
+
},
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
// `orc gotcha card --files … --json --full` — a match, and the zero-match ANSWER.
|
|
426
|
+
const gotchaCard = {
|
|
427
|
+
ok: true,
|
|
428
|
+
lane: null,
|
|
429
|
+
text: "gotchas (3 of 11 match):\nG-006 PR 142 · thread 3 · src/routes/**/*.js · a handler returns 200 on a validation error → return 422 with the field name (3×)\nG-001 repair · tests/**/*.test.js · `npm test` never exits; CI times out at 10 minutes → close the http server in afterAll and await it (7×)\ndo not flag: G-010 · client/src/i18n/** · long translation files flagged as too long (the team disputed this 3×)",
|
|
430
|
+
ids: ["G-006", "G-001", "G-010"],
|
|
431
|
+
matched: 3,
|
|
432
|
+
known: 11,
|
|
433
|
+
dropped: 0,
|
|
434
|
+
orphaned: ["G-011"],
|
|
435
|
+
quiet: 1,
|
|
436
|
+
budget: 600,
|
|
437
|
+
tokens: 96,
|
|
438
|
+
rows: [
|
|
439
|
+
{ id: "G-006", type: "flag", text: "G-006 PR 142 · thread 3 · src/routes/**/*.js · a handler returns 200 on a validation error → return 422 with the field name (3×)", rank: 2.1, miss: false, kept: true, dropped: null },
|
|
440
|
+
{ id: "G-001", type: "flag", text: "G-001 repair · tests/**/*.test.js · `npm test` never exits; CI times out at 10 minutes → close the http server in afterAll and await it (7×)", rank: 1.7, miss: false, kept: true, dropped: null },
|
|
441
|
+
{ id: "G-010", type: "suppress", text: "do not flag: G-010 · client/src/i18n/** · long translation files flagged as too long (the team disputed this 3×)", rank: 0.9, miss: false, kept: true, dropped: null },
|
|
442
|
+
],
|
|
443
|
+
orphaned_rows: [{ id: "G-011", why: "its scope matches no tracked file" }],
|
|
444
|
+
};
|
|
445
|
+
const gotchaCardNone = { ok: true, lane: null, text: "", ids: [], matched: 0, known: 11, dropped: 0, orphaned: [], quiet: 1, budget: 600, tokens: 0 };
|
|
446
|
+
|
|
447
|
+
// `orc gotcha quality --json` — above the floor, and below it (exit 1).
|
|
448
|
+
const SERIES = [0.48, 0.5, 0.46, 0.55, 0.58, 0.52, 0.6, 0.63, 0.61, 0.66, 0.69, 0.71];
|
|
449
|
+
const P3 = [4.1, 3.8, 3.9, 3.2, 3.0, 2.8, 2.6, 2.3, 2.1, 1.9, 1.7, 1.6];
|
|
450
|
+
const gotchaQuality = {
|
|
451
|
+
ok: true,
|
|
452
|
+
window_days: 90,
|
|
453
|
+
reviews: 12,
|
|
454
|
+
reviews_traced: 12,
|
|
455
|
+
reviews_observed: 9,
|
|
456
|
+
by_reviewer: { orc: 12, "/code-review": 2 },
|
|
457
|
+
project_reviews: 2,
|
|
458
|
+
// v2.1.0 W6 — `orc fix record`: the fixes made after a review, and the misses.
|
|
459
|
+
fixes: {
|
|
460
|
+
total: 5,
|
|
461
|
+
by_introduced_by: { orc: 2, ai: 1, human: 1, unknown: 1 },
|
|
462
|
+
by_source: { sonar: 2, defect: 2, ci: 1 },
|
|
463
|
+
causes: [
|
|
464
|
+
{ id: "sonar", n: 2, share: 0.4 },
|
|
465
|
+
{ id: "orc", n: 1, share: 0.2 },
|
|
466
|
+
{ id: "ai", n: 1, share: 0.2 },
|
|
467
|
+
{ id: "other", n: 1, share: 0.2 },
|
|
468
|
+
],
|
|
469
|
+
},
|
|
470
|
+
misses: {
|
|
471
|
+
total: 1,
|
|
472
|
+
by_category: [{ category: "functional.logic", n: 1 }],
|
|
473
|
+
list: [
|
|
474
|
+
{ obs: "9f2c41ab", at: new Date(NOW - 3 * DAY).toISOString().slice(0, 10), path: "src/orders/total.ts", lines: [40, 58], source: "sonar", rule: "sonar:typescript:S3776", category: "functional.logic", introduced_by: "orc", missed_by: "run-mini-total-290926-101500", fix_run: "run-quick-total-fix-021026-091200" },
|
|
475
|
+
],
|
|
476
|
+
},
|
|
477
|
+
floor: 5,
|
|
478
|
+
below_floor: false,
|
|
479
|
+
findings: 118,
|
|
480
|
+
categories: [
|
|
481
|
+
{ category: "security", findings: 14, addressed: 12, disputed: 1, wontfix: 1, open: 0, acceptance: 0.857, noisy: false },
|
|
482
|
+
{ category: "functional.logic", findings: 31, addressed: 21, disputed: 6, wontfix: 2, open: 2, acceptance: 0.724, noisy: false },
|
|
483
|
+
{ category: "test", findings: 22, addressed: 10, disputed: 8, wontfix: 2, open: 2, acceptance: 0.5, noisy: false },
|
|
484
|
+
{ category: "evolvability.structure", findings: 28, addressed: 7, disputed: 16, wontfix: 3, open: 2, acceptance: 0.269, noisy: true },
|
|
485
|
+
{ category: "evolvability.documentation", findings: 23, addressed: 9, disputed: 9, wontfix: 3, open: 2, acceptance: 0.429, noisy: false },
|
|
486
|
+
],
|
|
487
|
+
gotchas: [{ id: "G-001", helpful: 4, harmful: 0, retire: false }, { id: "G-010", helpful: 0, harmful: 3, retire: true }],
|
|
488
|
+
p3_per_review: 2.75,
|
|
489
|
+
trend: { first_half: 0.53, second_half: 0.67, direction: "up" },
|
|
490
|
+
target: 0.6,
|
|
491
|
+
bands: { ok: 0.6, warn: 0.35 },
|
|
492
|
+
series: SERIES.map((a, i) => ({ run: `run-orc-review-${i + 1}`, at: new Date(NOW - (12 - i) * 4 * DAY).toISOString(), findings: 10, acceptance: a, p3: P3[i] })),
|
|
493
|
+
floor_line: null,
|
|
494
|
+
};
|
|
495
|
+
const gotchaQualityLow = {
|
|
496
|
+
ok: true,
|
|
497
|
+
window_days: 30,
|
|
498
|
+
reviews: 3,
|
|
499
|
+
// v2.1.0 — one review counted from its trace only (a clean review).
|
|
500
|
+
reviews_traced: 3,
|
|
501
|
+
reviews_observed: 2,
|
|
502
|
+
by_reviewer: { orc: 3 },
|
|
503
|
+
project_reviews: 0,
|
|
504
|
+
fixes: { total: 0, by_introduced_by: { orc: 0, ai: 0, human: 0, unknown: 0 }, by_source: {}, causes: [{ id: "sonar", n: 0, share: 0 }, { id: "orc", n: 0, share: 0 }, { id: "ai", n: 0, share: 0 }, { id: "other", n: 0, share: 0 }] },
|
|
505
|
+
misses: { total: 0, by_category: [], list: [] },
|
|
506
|
+
floor: 5,
|
|
507
|
+
below_floor: true,
|
|
508
|
+
findings: 19,
|
|
509
|
+
categories: [{ category: "test", findings: 7, addressed: 3, disputed: 3, wontfix: 0, open: 1, acceptance: 0.5, noisy: false }],
|
|
510
|
+
gotchas: [],
|
|
511
|
+
p3_per_review: 2.33,
|
|
512
|
+
trend: { first_half: null, second_half: 0.5, direction: null },
|
|
513
|
+
target: 0.6,
|
|
514
|
+
bands: { ok: 0.6, warn: 0.35 },
|
|
515
|
+
series: [
|
|
516
|
+
{ run: "run-orc-review-a", at: new Date(NOW - 9 * DAY).toISOString(), findings: 6, acceptance: 0.5, p3: 2 },
|
|
517
|
+
{ run: "run-orc-review-b", at: new Date(NOW - 5 * DAY).toISOString(), findings: 7, acceptance: null, p3: 3 },
|
|
518
|
+
{ run: "run-orc-review-c", at: new Date(NOW - 1 * DAY).toISOString(), findings: 6, acceptance: 0.6, p3: 2 },
|
|
519
|
+
],
|
|
520
|
+
floor_line: "5 reviews needed — 3 so far.",
|
|
521
|
+
};
|
|
522
|
+
|
|
523
|
+
// One candidate, every key `publicCand` emits.
|
|
524
|
+
function cand(o) {
|
|
525
|
+
return Object.assign({ id: "", kind: "candidate", key: "", rule: null, sig: null, category: null, scope: null, scope_refused: null, lang: null, source: "review", cases: 0, addressed: 0, disputed: 0, prs: 0, strong: false, watch: false, severity: null, cwe: null, last_at: new Date(NOW - 2 * DAY).toISOString(), promote: false, promote_rule: null, why: null, needs: null, obs: [] }, o);
|
|
526
|
+
}
|
|
527
|
+
// `orc gotcha list --candidates --json` — a candidate and a proposed suppression.
|
|
528
|
+
const gotchaCandidates = {
|
|
529
|
+
ok: true,
|
|
530
|
+
count: 3,
|
|
531
|
+
candidates: [
|
|
532
|
+
cand({ id: "C-7e11a0", kind: "candidate", key: "pr|a missing await on a repository call", source: "pr", rule: "PR 151 · thread 2", sig: "a missing await on a repository call", category: "functional.timing", severity: "P2", scope: "src/repos/**/*.ts", cases: 2, addressed: 2, disputed: 0, prs: 1, strong: true, watch: true, needs: "1 more addressed case in another PR, or your yes" }),
|
|
533
|
+
],
|
|
534
|
+
suppressions: [
|
|
535
|
+
cand({ id: "C-2b91e0", kind: "suppression", key: "suppress|long test names", source: "dismissal", sig: "long test names", category: "evolvability.documentation", severity: "P3", scope: "**/*.spec.*", cases: 3, addressed: 0, disputed: 3, prs: 3, needs: "a person accepts it: orc gotcha accept <id> (a suppression is never automatic)" }),
|
|
536
|
+
cand({ id: "C-a04c55", kind: "suppression", key: "suppress|long translation files", source: "dismissal", sig: "long translation files", category: "evolvability.structure", severity: "P3", scope: "client/src/i18n/**", cases: 4, addressed: 0, disputed: 4, prs: 2, needs: "a person accepts it: orc gotcha accept <id> (a suppression is never automatic)" }),
|
|
537
|
+
],
|
|
538
|
+
project_actions: [],
|
|
539
|
+
retire: [{ id: "G-010", helpful: 0, harmful: 3, proposal: "retire — ORC never applies it; delete the block yourself" }],
|
|
540
|
+
quiet: ["G-003", "G-009"],
|
|
541
|
+
orphaned: [{ id: "G-011", why: "its scope matches no tracked file" }],
|
|
542
|
+
observations: 164,
|
|
543
|
+
rules: { cases: 3, prs: 2, window_days: 90, jaccard_min: 0.6, suppress_disputes: 2, do_line_cases: 5 },
|
|
544
|
+
};
|
|
545
|
+
|
|
546
|
+
module.exports = {
|
|
547
|
+
habitsPropose,
|
|
548
|
+
habitsObserve,
|
|
549
|
+
habitsOff,
|
|
550
|
+
habitsEmpty,
|
|
551
|
+
habitLog,
|
|
552
|
+
habitLogEmpty,
|
|
553
|
+
habitStates,
|
|
554
|
+
habitPoints,
|
|
555
|
+
gotchaExtraEntries,
|
|
556
|
+
gotchaPanel,
|
|
557
|
+
gotchaCard,
|
|
558
|
+
gotchaCardNone,
|
|
559
|
+
gotchaQuality,
|
|
560
|
+
gotchaQualityLow,
|
|
561
|
+
gotchaCandidates,
|
|
562
|
+
};
|