@azure-id/orc 2.1.0 → 2.2.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.
Files changed (153) hide show
  1. package/CHANGELOG.md +374 -0
  2. package/README.md +49 -36
  3. package/bin/build-agents.js +7 -5
  4. package/bin/cli.js +1006 -235
  5. package/bin/fix.js +21 -18
  6. package/bin/graph-extract.js +314 -6
  7. package/bin/graph-gain.js +83 -2
  8. package/bin/graph-map.js +23 -1
  9. package/bin/graph-notes.js +1 -1
  10. package/bin/graph-query.js +1362 -37
  11. package/bin/graph-resolve.js +1 -1
  12. package/bin/graph-shard.js +29 -6
  13. package/bin/graph-signals.js +5 -3
  14. package/bin/graph.js +7 -3
  15. package/bin/habit.js +1 -1
  16. package/bin/pricing.json +8 -1
  17. package/bin/trace-write.js +40 -11
  18. package/bin/verify-contracts.js +169 -60
  19. package/bin/verify-package.js +3 -3
  20. package/bin/webui/api.js +8 -0
  21. package/bin/webui/fixtures/extra.js +9 -9
  22. package/bin/webui/fixtures/flow.js +1 -1
  23. package/bin/webui/fixtures/index.js +2 -2
  24. package/bin/webui/fixtures/knowledge.js +8 -1
  25. package/bin/webui/fixtures/pact.js +112 -111
  26. package/bin/webui/fixtures/stats.js +2 -2
  27. package/bin/webui/i18n/en/knowledge.json +2 -0
  28. package/bin/webui/i18n/id/knowledge.json +2 -0
  29. package/bin/webui/js/panels/knowledge.js +17 -0
  30. package/guides/code-graph-benefit.md +116 -0
  31. package/guides/configuration.md +150 -0
  32. package/guides/documents.md +262 -0
  33. package/guides/extra-models.md +448 -0
  34. package/guides/habits-and-gotchas.md +152 -0
  35. package/guides/knowledge-reads.md +190 -0
  36. package/guides/model-selection.md +186 -0
  37. package/guides/rules.md +305 -0
  38. package/guides/status-line.md +344 -0
  39. package/mock-run/a-normal-day.md +2 -2
  40. package/mock-run/extra-slots.md +177 -177
  41. package/mock-run/orc-cli.md +3 -2
  42. package/mock-run/orc-doc.md +452 -448
  43. package/mock-run/orc-fast.md +2 -2
  44. package/mock-run/orc-quick.md +146 -146
  45. package/mock-run/orc.md +4 -4
  46. package/package.json +2 -1
  47. package/templates/agents/MODEL-MAPPING.md +12 -12
  48. package/templates/agents/{orc-executor-haiku-4-5.md → orc-executor-haiku-5-high.md} +21 -8
  49. package/templates/agents/orc-executor-opus-4-7-high.md +17 -5
  50. package/templates/agents/orc-executor-opus-4-7-med.md +17 -5
  51. package/templates/agents/orc-executor-opus-4-8-high.md +17 -5
  52. package/templates/agents/orc-executor-opus-5-high.md +17 -5
  53. package/templates/agents/orc-executor-opus-5-low.md +17 -5
  54. package/templates/agents/orc-executor-opus-5-med.md +17 -5
  55. package/templates/agents/orc-executor-sonnet-4-6-high.md +17 -5
  56. package/templates/agents/orc-executor-sonnet-5-high.md +17 -5
  57. package/templates/agents/orc-executor-sonnet-5-low.md +17 -5
  58. package/templates/agents/orc-executor-sonnet-5-med.md +17 -5
  59. package/templates/agents/{orc-graph-noter-sonnet-4-6-med.md → orc-graph-noter-haiku-5-high.md} +4 -4
  60. package/templates/agents/orc-planner-mini-opus-5-med.md +3 -1
  61. package/templates/agents/orc-planner-mini-sonnet-5-high.md +3 -1
  62. package/templates/agents/orc-planner-opus-5-med.md +3 -1
  63. package/templates/agents/{orc-recon-sonnet-4-6-med.md → orc-recon-sonnet-5-med.md} +4 -4
  64. package/templates/agents/{orc-trace-writer-haiku-4-5.md → orc-trace-writer-haiku-5-high.md} +4 -3
  65. package/templates/commands/orc-doc.md +128 -128
  66. package/templates/commands/orc-export.md +51 -46
  67. package/templates/commands/orc-fast.md +10 -10
  68. package/templates/hooks/README.md +8 -3
  69. package/templates/hooks/orc-effort-guard.js +105 -27
  70. package/templates/hooks/orc-graph-hook.js +252 -4
  71. package/templates/hooks/orc-statusline.js +13 -6
  72. package/templates/hooks/orc-trace.js +1 -1
  73. package/templates/skills/_shared/README.md +2 -2
  74. package/templates/skills/_shared/code-graph.md +185 -251
  75. package/templates/skills/_shared/extra-dispatch.md +4 -4
  76. package/templates/skills/_shared/lane-contract.md +7 -3
  77. package/templates/skills/_shared/opus5-only.md +3 -3
  78. package/templates/skills/_shared/phases/execution.md +13 -11
  79. package/templates/skills/_shared/phases/planning.md +27 -9
  80. package/templates/skills/_shared/phases/preflight.md +3 -3
  81. package/templates/skills/_shared/phases/review.md +4 -3
  82. package/templates/skills/_shared/phases/ship.md +7 -10
  83. package/templates/skills/_shared/phases/summary.md +2 -3
  84. package/templates/skills/_shared/phases/trace-verbs.md +21 -16
  85. package/templates/skills/_shared/phases/trace.md +3 -3
  86. package/templates/skills/_shared/phases/wiki-consult.md +2 -2
  87. package/templates/skills/_shared/pr-templates.md +108 -106
  88. package/templates/skills/_shared/read-ladder.md +8 -2
  89. package/templates/skills/_shared/return-validation.md +10 -6
  90. package/templates/skills/_shared/review-slice.md +1 -1
  91. package/templates/skills/_shared/stack-plan.md +135 -135
  92. package/templates/skills/_shared/wait.md +14 -2
  93. package/templates/skills/context-combiner/SKILL.md +2 -2
  94. package/templates/skills/orc/SKILL.md +7 -7
  95. package/templates/skills/orc/config.md +2 -2
  96. package/templates/skills/orc/examples/full-run-mock.md +7 -7
  97. package/templates/skills/orc/references/effort-and-mode.md +222 -222
  98. package/templates/skills/orc/schemas/planning-output.md +3 -0
  99. package/templates/skills/orc-aftermath/SKILL.md +15 -15
  100. package/templates/skills/orc-analyze/SKILL.md +2 -2
  101. package/templates/skills/orc-analyze-mini/SKILL.md +2 -2
  102. package/templates/skills/orc-boundary/SKILL.md +15 -15
  103. package/templates/skills/orc-boundary/references/card.md +81 -78
  104. package/templates/skills/orc-boundary/references/gate.md +113 -113
  105. package/templates/skills/orc-brainstorm/SKILL.md +15 -15
  106. package/templates/skills/orc-budget/SKILL.md +15 -15
  107. package/templates/skills/orc-challenge/README.md +1 -1
  108. package/templates/skills/orc-challenge/SKILL.md +16 -16
  109. package/templates/skills/orc-challenge/examples/council-full-roster.md +1 -1
  110. package/templates/skills/orc-claude/SKILL.md +4 -4
  111. package/templates/skills/orc-claude/examples/claude-run-mock.md +1 -1
  112. package/templates/skills/orc-diy/SKILL.md +2 -2
  113. package/templates/skills/orc-diy/references/blocks/wiki.md +26 -26
  114. package/templates/skills/orc-diy/references/flow-schema.md +2 -2
  115. package/templates/skills/orc-doc/README.md +2 -2
  116. package/templates/skills/orc-doc/SKILL.md +501 -490
  117. package/templates/skills/orc-doc/examples/orc-doc-prd-run.md +12 -1
  118. package/templates/skills/orc-doc/references/chunking.md +6 -4
  119. package/templates/skills/orc-doc/references/gates.md +311 -311
  120. package/templates/skills/orc-doc/references/resume-protocol.md +229 -228
  121. package/templates/skills/orc-explain/SKILL.md +88 -88
  122. package/templates/skills/orc-export/SKILL.md +190 -187
  123. package/templates/skills/orc-fast/SKILL.md +17 -14
  124. package/templates/skills/orc-grill/SKILL.md +16 -16
  125. package/templates/skills/orc-grill/references/grill-doc.md +1 -1
  126. package/templates/skills/orc-handoff/SKILL.md +11 -11
  127. package/templates/skills/orc-learn/SKILL.md +13 -13
  128. package/templates/skills/orc-learn/examples/learn-run-mock.md +2 -2
  129. package/templates/skills/orc-mini/SKILL.md +12 -12
  130. package/templates/skills/orc-mini/examples/mini-run-mock.md +4 -5
  131. package/templates/skills/orc-pact/SKILL.md +15 -15
  132. package/templates/skills/orc-pact/references/gate.md +70 -70
  133. package/templates/skills/orc-pattern/SKILL.md +3 -3
  134. package/templates/skills/orc-poly/SKILL.md +4 -4
  135. package/templates/skills/orc-poly/examples/poly-run-mock.md +51 -51
  136. package/templates/skills/orc-pr-driver/SKILL.md +4 -3
  137. package/templates/skills/orc-pr-driver/references/orc-run-split.md +108 -99
  138. package/templates/skills/orc-pr-setup/SKILL.md +2 -2
  139. package/templates/skills/orc-quick/README.md +11 -12
  140. package/templates/skills/orc-quick/SKILL.md +29 -32
  141. package/templates/skills/orc-quick/references/context-doc.md +5 -5
  142. package/templates/skills/orc-quick/references/dispatch-gate.md +10 -10
  143. package/templates/skills/orc-quick/references/gh-mode.md +2 -1
  144. package/templates/skills/orc-quick/references/look.md +34 -12
  145. package/templates/skills/orc-retro/SKILL.md +2 -2
  146. package/templates/skills/orc-retro/examples/retro-mock.md +2 -2
  147. package/templates/skills/orc-route/SKILL.md +2 -2
  148. package/templates/skills/orc-test/SKILL.md +6 -3
  149. package/templates/skills/orc-verify/SKILL.md +2 -2
  150. package/templates/skills/orc-wait/SKILL.md +10 -2
  151. package/templates/skills/orc-wiki/SKILL.md +4 -4
  152. package/templates/skills/orc-wiki/references/pattern-prewarm.md +19 -19
  153. package/templates/agents/orc-executor-sonnet-4-6-med.md +0 -155
package/bin/webui/api.js CHANGED
@@ -1294,6 +1294,14 @@ async function handleApi(req, res, url, ctx) {
1294
1294
  const build = READS[route];
1295
1295
  if (!build) return json(res, 404, { error: "unknown endpoint " + route });
1296
1296
  const out = readCli(build(q), ctx);
1297
+ // v2.2.0 — `graph status` without --if-enabled answers the INDEX state, so
1298
+ // a `semi` project looks like `on`. The configured mode is passed through
1299
+ // from `orc config get` so the panel can show the SEMI badge.
1300
+ if (route === "/api/graph" && out.ok && out.data && !out.data.mode) {
1301
+ const cfgRes = readCli(["config", "get", "code_graph"], ctx);
1302
+ const row = cfgRes.data && Array.isArray(cfgRes.data.keys) ? cfgRes.data.keys.find((k) => k.key === "code_graph") : null;
1303
+ if (row) out.data.mode = String(row.value).toLowerCase();
1304
+ }
1297
1305
  // v0.49.2 — a read that produced no parseable object still has to SAY why.
1298
1306
  // The body already carried `stderr` and `stdout`; nothing named `error`, so
1299
1307
  // the client fell through to "request failed (500)" and one corrupt ledger
@@ -838,10 +838,10 @@ const extraRole = {
838
838
  verify_state: "VERIFIED", verify_age_days: 1, model_known: false,
839
839
  meaning: "the user picks the agent for every entry anyway, so a foreign worker is one more option on a menu they already read.",
840
840
  asks: true, announce_point: "the dispatch gate — offered as a third option, never a default",
841
- claude: { via: "claude", agent: "orc-executor-sonnet-4-6-med", agents: ["orc-executor-sonnet-4-6-med", "orc-executor-opus-5-low"], table: "shipped" },
841
+ claude: { via: "claude", agent: "orc-executor-sonnet-5-med", agents: ["orc-executor-sonnet-5-med", "orc-executor-opus-5-low"], table: "shipped" },
842
842
  resolved: "extra", held_back: null,
843
- why: "slot row quick-executor holds this position and outranks orc-executor-sonnet-4-6-med.",
844
- announce: "quick-executor (/orc-quick) → deepseek/deepseek-coder via api (profile cheap) — displaces orc-executor-sonnet-4-6-med; this sends the slice to a third party.",
843
+ why: "slot row quick-executor holds this position and outranks orc-executor-sonnet-5-med.",
844
+ announce: "quick-executor (/orc-quick) → deepseek/deepseek-coder via api (profile cheap) — displaces orc-executor-sonnet-5-med; this sends the slice to a third party.",
845
845
  next: null,
846
846
  },
847
847
  {
@@ -851,10 +851,10 @@ const extraRole = {
851
851
  verify_state: "STALE", verify_age_days: 15, model_known: true,
852
852
  meaning: "one executor, one slice, a build+test smoke gate behind it — the checks that catch a bad implementation here are engine-blind.",
853
853
  asks: false, announce_point: "the F0 preflight `extra:` line, before wave 1",
854
- claude: { via: "claude", agent: "orc-executor-sonnet-4-6-high", agents: ["orc-executor-sonnet-4-6-high"], table: "shipped" },
854
+ claude: { via: "claude", agent: "orc-executor-sonnet-5-med", agents: ["orc-executor-sonnet-5-med"], table: "shipped" },
855
855
  resolved: "extra", held_back: null,
856
- why: "slot row fast-executor holds this position and outranks orc-executor-sonnet-4-6-high; verification is 15d old (STALE — still routes, re-pinged before the wave).",
857
- announce: "fast-executor (/orc-fast) → zai/glm-4.6 via claude-shim (profile glm) — displaces orc-executor-sonnet-4-6-high; this sends the slice to a third party.",
856
+ why: "slot row fast-executor holds this position and outranks orc-executor-sonnet-5-med; verification is 15d old (STALE — still routes, re-pinged before the wave).",
857
+ announce: "fast-executor (/orc-fast) → zai/glm-4.6 via claude-shim (profile glm) — displaces orc-executor-sonnet-5-med; this sends the slice to a third party.",
858
858
  next: null,
859
859
  },
860
860
  {
@@ -876,7 +876,7 @@ const extraRole = {
876
876
  slot: "doc-checker", lane: "/orc-doc", routed: false,
877
877
  profile: null, model: null, small_model: null, max_turns: null, added_at: null,
878
878
  provider: null, engine: null, verify_state: null, verify_age_days: null, model_known: null,
879
- meaning: "the checker reads one bounded part and reports; it rewrites nothing, so a finding it makes is a finding you read.",
879
+ meaning: "the checker reads only the bounded part files of one slice and reports; it rewrites nothing, so a finding it makes is a finding you read.",
880
880
  asks: false, announce_point: "before the wave",
881
881
  claude: { via: "claude", agent: "orc-doc-checker-opus-5-low", agents: ["orc-doc-checker-opus-5-low"], table: "shipped" },
882
882
  resolved: "claude", held_back: null,
@@ -962,7 +962,7 @@ const extraLanes = {
962
962
  {
963
963
  lane: "/orc-fast", shape: "slot", agent: null, routes: "roles",
964
964
  slots: [
965
- { slot: "fast-executor", routes: true, profile: "glm", model: "glm-4.6", claude: "orc-executor-sonnet-4-6-high", held_back: null, why: "slot row fast-executor holds this position and outranks orc-executor-sonnet-4-6-high." },
965
+ { slot: "fast-executor", routes: true, profile: "glm", model: "glm-4.6", claude: "orc-executor-sonnet-5-med", held_back: null, why: "slot row fast-executor holds this position and outranks orc-executor-sonnet-5-med." },
966
966
  ],
967
967
  detail: "fast-executor is held by a non-Claude worker; every position with no row stays on its pinned Claude agent.",
968
968
  },
@@ -976,7 +976,7 @@ const extraLanes = {
976
976
  // user gets to make, per entry.
977
977
  lane: "/orc-quick", shape: "gated-choice", agent: null, routes: "offered",
978
978
  slots: [
979
- { slot: "quick-executor", routes: true, profile: "cheap", model: "deepseek-chat", claude: "orc-executor-sonnet-4-6-med", held_back: null, why: "slot row quick-executor holds this position and outranks orc-executor-sonnet-4-6-med." },
979
+ { slot: "quick-executor", routes: true, profile: "cheap", model: "deepseek-chat", claude: "orc-executor-sonnet-5-med", held_back: null, why: "slot row quick-executor holds this position and outranks orc-executor-haiku-5-high." },
980
980
  ],
981
981
  detail: "quick-executor is OFFERED as one more option at the dispatch gate. It never becomes a default and never sticks — this lane asks before every dispatch.",
982
982
  },
@@ -31,7 +31,7 @@ const diy = {
31
31
  { key: "planning", value: "own-planner", default: "auto", is_set: true, desc: "Planning route.", options: ["auto", "own-planner", "superpowers", "openspec"] },
32
32
  { key: "pattern", value: "ask", default: "ask", is_set: false, desc: "Code-pattern gate on a cache miss.", options: ["ask", "off", "on"] },
33
33
  { key: "scoring", value: "on", default: "on", is_set: false, desc: "Rubric scoring.", options: ["on", "off"] },
34
- { key: "fixed_executor", value: "", default: "", is_set: false, desc: "Executor used for every task when scoring is off.", options: ["orc-executor-haiku-4-5", "orc-executor-sonnet-4-6-med", "orc-executor-sonnet-5-high", "orc-executor-opus-4-8-high", "orc-executor-opus-5-high"] },
34
+ { key: "fixed_executor", value: "", default: "", is_set: false, desc: "Executor used for every task when scoring is off.", options: ["orc-executor-haiku-5-high", "orc-executor-sonnet-5-high", "orc-executor-opus-4-8-high", "orc-executor-opus-5-high"] },
35
35
  { key: "review", value: "blocking-only", default: "full", is_set: true, desc: "Review phase depth.", options: ["on", "off", "blocking-only"] },
36
36
  { key: "security", value: "off", default: "off", is_set: false, desc: "Security pass.", options: ["off", "ask", "on", "always"] },
37
37
  { key: "verify", value: "smoke", default: "full", is_set: true, desc: "Verification depth.", options: ["full", "off", "smoke"] },
@@ -21,7 +21,7 @@
21
21
  // case here; it is never an edit to a 1 700-line module.
22
22
  const { PROJECT, doctor, where } = require("./shell.js");
23
23
  const { config } = require("./settings.js");
24
- const { wiki, wikiDocs, wikiShow, wikiCoverage, wikiCoverageFull, wikiUnregistered, wikiPlan, wikiDebt, wikiUsage, patterns, patternShow, gotchas, gotchasArchived, gotchaPrunePreview, wikiImpact, graph, graphGain, graphGainMeasured } = require("./knowledge.js");
24
+ const { wiki, wikiDocs, wikiShow, wikiCoverage, wikiCoverageFull, wikiUnregistered, wikiPlan, wikiDebt, wikiUsage, patterns, patternShow, gotchas, gotchasArchived, gotchaPrunePreview, wikiImpact, graph, graphSemi, graphGain, graphGainMeasured } = require("./knowledge.js");
25
25
  const { runs, runDetail, runDetailClosed, aftermath } = require("./runs.js");
26
26
  const { stats, budgetForecast, budgetRates } = require("./stats.js");
27
27
  const { pact } = require("./pact.js");
@@ -309,7 +309,7 @@ module.exports.get = function get(route, q) {
309
309
  return wikiImpact;
310
310
  // v1.8.0 — the code graph, DRIFTED (the state the card must be designed for).
311
311
  case "/api/graph":
312
- return graph;
312
+ return q && q.mode === "semi" ? graphSemi : graph;
313
313
  // v1.8.2 W4b — the gain meter, and the A/B behind its second button.
314
314
  case "/api/graph/gain":
315
315
  return graphGain;
@@ -309,6 +309,8 @@ const graph = {
309
309
  generation: 42,
310
310
  gen_id: "c878981d",
311
311
  state: "drifted",
312
+ // v2.2.0 — the configured `code_graph`, added by the API (not by the CLI).
313
+ mode: "on",
312
314
  behind: { added: 1, changed: 3, deleted: 0 },
313
315
  engine_stale: false,
314
316
  auto_update: true,
@@ -334,6 +336,11 @@ const graph = {
334
336
 
335
337
  // v1.8.2 W4b — `orc graph gain --json`. The fixture carries the ESTIMATE word
336
338
  // and a RANGE, because those are the two things the card must never lose.
339
+ // v2.2.0 — the same index under `code_graph: semi`. `graph status` (no
340
+ // --if-enabled) answers the index state; the API adds `mode` from the config.
341
+ // Served on /api/graph?mode=semi so the default tab stays DRIFTED.
342
+ const graphSemi = { ...graph, state: "fresh", behind: { added: 0, changed: 0, deleted: 0 }, mode: "semi" };
343
+
337
344
  const graphGain = {
338
345
  ok: true,
339
346
  state: "rows",
@@ -376,4 +383,4 @@ const graphGainMeasured = {
376
383
  "executor windows and session totals are kept apart: the main session is 74–80% of a run and the graph never touches it. Every delta is printed beside the OFF group's own spread — a delta smaller than that spread is noise, not a result.",
377
384
  };
378
385
 
379
- module.exports = { wiki, wikiDocs, wikiShow, wikiCoverage, wikiCoverageFull, wikiUnregistered, wikiPlan, wikiDebt, wikiUsage, patterns, patternShow, gotchas, gotchasArchived, gotchaPrunePreview, wikiImpact, graph, graphGain, graphGainMeasured };
386
+ module.exports = { wiki, wikiDocs, wikiShow, wikiCoverage, wikiCoverageFull, wikiUnregistered, wikiPlan, wikiDebt, wikiUsage, patterns, patternShow, gotchas, gotchasArchived, gotchaPrunePreview, wikiImpact, graph, graphSemi, graphGain, graphGainMeasured };
@@ -1,111 +1,112 @@
1
- "use strict";
2
- /* fixtures/pact.js — canned data for `orc ui --fixtures`.
3
- The invariant ledger, carrying one of each state — BROKEN, DRIFTED,
4
- UNCHECKABLE, HOLDING.
5
-
6
- THE RULE FOR EVERY FILE IN HERE: carry ONE OF EVERY STATE, including the
7
- ugly ones. You cannot DESIGN a STALE chip on a fresh wiki, and a state
8
- with no fixture is a state nobody has ever looked at. A per-state count
9
- test asserts this, so a new state cannot ship without one.
10
-
11
- Shapes MUST match what `bin/cli.js --json` really emits — a drifted
12
- fixture is worse than no fixture. */
13
-
14
- const { PROJECT } = require("./shell.js");
15
-
16
- const pact = {
17
- ok: true,
18
- ledger: PROJECT + "/.claude/orc/pact/ledger.json",
19
- doc: PROJECT + "/PACT.md",
20
- doc_exists: true,
21
- entries: 5,
22
- retired: 1,
23
- counts: { HOLDING: 2, DRIFTED: 1, UNCHECKABLE: 1, BROKEN: 1 },
24
- line: "pact: 2 holding · 1 drifted · 1 uncheckable · 1 BROKEN",
25
- rows: [
26
- {
27
- id: "PACT-014",
28
- statement: "A payment is never written to the ledger twice for one idempotency key.",
29
- origin: { lane: "orc-grill", run: "run-grill-checkout-100826-141130", kind: "constraint" },
30
- anchors: ["src/payments/ledger.ts:88", "src/payments/idempotency.ts"],
31
- check: { kind: "test", ref: "npm test -- idempotency" },
32
- verified_commit: "8a62b4f1c9",
33
- confidence: "high",
34
- last_check: { status: "fail", commit: "8a62b4f1c9", at: "09-08-2026 11:20:04", ref: "npm test -- idempotency" },
35
- // A real-looking failure, not a placeholder: the panel has to lay out a
36
- // multi-line check output that does not fit its card.
37
- history: [
38
- { at: "09-08-2026 11:20:04", status: "fail", commit: "8a62b4f1c9" },
39
- { at: "02-08-2026 09:14:51", status: "pass", commit: "c273793aa1" },
40
- ],
41
- retired: false,
42
- state: "BROKEN",
43
- why: "check failed at 8a62b4f1 (09-08-2026 11:20:04)",
44
- distance: 3,
45
- },
46
- {
47
- id: "PACT-002",
48
- statement: "Refund windows are configured, never hardcoded.",
49
- origin: { lane: "orc-brainstorm", run: "run-brainstorm-refunds-010826-101010", kind: "constraint" },
50
- anchors: ["src/billing/refund.ts"],
51
- check: { kind: "grep", ref: "REFUND_WINDOW_DAYS" },
52
- verified_commit: "c273793aa1",
53
- confidence: "medium",
54
- last_check: { status: "pass", commit: "c273793aa1", at: "01-08-2026 10:11:02", ref: "REFUND_WINDOW_DAYS" },
55
- history: [{ at: "01-08-2026 10:11:02", status: "pass", commit: "c273793aa1" }],
56
- retired: false,
57
- state: "DRIFTED",
58
- why: "6 commits since c273793a touched 1 anchored file",
59
- distance: 6,
60
- },
61
- {
62
- id: "PACT-007",
63
- statement: "The admin export never contains a raw email address.",
64
- origin: { lane: "user", run: null, kind: "constraint" },
65
- anchors: ["src/admin/export.ts"],
66
- check: { kind: "manual", ref: null },
67
- verified_commit: "783f6971aa",
68
- confidence: "low",
69
- last_check: null,
70
- history: [],
71
- retired: false,
72
- state: "UNCHECKABLE",
73
- // The long day count: an UNCHECKABLE promise nobody has looked at for
74
- // months is the case this state exists to make visible.
75
- why: "no cheap check exists — this promise is held by review, not by a runner",
76
- distance: null,
77
- },
78
- {
79
- id: "PACT-001",
80
- statement: "Every outbound webhook is signed with the tenant's current secret.",
81
- origin: { lane: "orc", run: "run-orc-webhooks-120726-084500", kind: "constraint" },
82
- anchors: ["src/webhooks/sign.ts:40"],
83
- check: { kind: "command", ref: "npm run test:webhooks" },
84
- verified_commit: "e9dad01bb2",
85
- confidence: "high",
86
- last_check: { status: "pass", commit: "e9dad01bb2", at: "05-08-2026 16:02:11", ref: "npm run test:webhooks" },
87
- history: [{ at: "05-08-2026 16:02:11", status: "pass", commit: "e9dad01bb2" }],
88
- retired: false,
89
- state: "HOLDING",
90
- why: "verified at e9dad01b; no commit since has touched its anchors",
91
- distance: 0,
92
- },
93
- {
94
- id: "PACT-009",
95
- statement: "Session cookies are always SameSite=Lax.",
96
- origin: { lane: "orc-grill", run: "run-grill-auth-200626-113000", kind: "constraint" },
97
- anchors: ["src/auth/session.ts"],
98
- check: { kind: "grep", ref: "SameSite=Lax" },
99
- verified_commit: "cc4778e0aa",
100
- confidence: "high",
101
- last_check: { status: "pass", commit: "cc4778e0aa", at: "21-06-2026 09:00:00", ref: "SameSite=Lax" },
102
- history: [{ at: "21-06-2026 09:00:00", status: "pass", commit: "cc4778e0aa" }],
103
- retired: false,
104
- state: "HOLDING",
105
- why: "verified at cc4778e0; no commit since has touched its anchors",
106
- distance: 0,
107
- },
108
- ],
109
- };
110
-
111
- module.exports = { pact };
1
+ "use strict";
2
+ /* fixtures/pact.js — canned data for `orc ui --fixtures`.
3
+ The invariant ledger, carrying one of each state — BROKEN, DRIFTED,
4
+ UNCHECKABLE, HOLDING.
5
+
6
+ THE RULE FOR EVERY FILE IN HERE: carry ONE OF EVERY STATE, including the
7
+ ugly ones. You cannot DESIGN a STALE chip on a fresh wiki, and a state
8
+ with no fixture is a state nobody has ever looked at. A per-state count
9
+ test asserts this, so a new state cannot ship without one.
10
+
11
+ Shapes MUST match what `bin/cli.js --json` really emits — a drifted
12
+ fixture is worse than no fixture. */
13
+
14
+ const { PROJECT } = require("./shell.js");
15
+
16
+ const pact = {
17
+ ok: true,
18
+ ledger: PROJECT + "/.claude/orc/pact/ledger.json",
19
+ doc: PROJECT + "/PACT.md",
20
+ doc_exists: true,
21
+ entries: 5,
22
+ retired: 1,
23
+ counts: { HOLDING: 2, DRIFTED: 1, UNCHECKABLE: 1, BROKEN: 1 },
24
+ line: "pact: 2 holding · 1 drifted · 1 uncheckable · 1 BROKEN",
25
+ rows: [
26
+ {
27
+ id: "PACT-014",
28
+ statement: "A payment is never written to the ledger twice for one idempotency key.",
29
+ origin: { lane: "orc-grill", run: "run-grill-checkout-100826-141130", kind: "constraint" },
30
+ anchors: ["src/payments/ledger.ts:88", "src/payments/idempotency.ts"],
31
+ check: { kind: "test", ref: "npm test -- idempotency" },
32
+ verified_commit: "8a62b4f1c9",
33
+ confidence: "high",
34
+ last_check: { status: "fail", commit: "8a62b4f1c9", at: "09-08-2026 11:20:04", ref: "npm test -- idempotency" },
35
+ // A real-looking failure, not a placeholder: the panel has to lay out a
36
+ // multi-line check output that does not fit its card.
37
+ history: [
38
+ { at: "09-08-2026 11:20:04", status: "fail", commit: "8a62b4f1c9" },
39
+ { at: "02-08-2026 09:14:51", status: "pass", commit: "c273793aa1" },
40
+ ],
41
+ retired: false,
42
+ state: "BROKEN",
43
+ why: "check failed at 8a62b4f1 (09-08-2026 11:20:04)",
44
+ distance: 3,
45
+ },
46
+ {
47
+ id: "PACT-002",
48
+ statement: "Refund windows are configured, never hardcoded.",
49
+ origin: { lane: "orc-brainstorm", run: "run-brainstorm-refunds-010826-101010", kind: "constraint" },
50
+ anchors: ["src/billing/refund.ts"],
51
+ check: { kind: "grep", ref: "REFUND_WINDOW_DAYS" },
52
+ verified_commit: "c273793aa1",
53
+ confidence: "medium",
54
+ last_check: { status: "pass", commit: "c273793aa1", at: "01-08-2026 10:11:02", ref: "REFUND_WINDOW_DAYS" },
55
+ history: [{ at: "01-08-2026 10:11:02", status: "pass", commit: "c273793aa1" }],
56
+ retired: false,
57
+ state: "DRIFTED",
58
+ why: "6 commits since c273793a touched 1 of 1 anchored file (src/billing/refund.ts)",
59
+ distance: 6,
60
+ touched_files: ["src/billing/refund.ts"],
61
+ },
62
+ {
63
+ id: "PACT-007",
64
+ statement: "The admin export never contains a raw email address.",
65
+ origin: { lane: "user", run: null, kind: "constraint" },
66
+ anchors: ["src/admin/export.ts"],
67
+ check: { kind: "manual", ref: null },
68
+ verified_commit: "783f6971aa",
69
+ confidence: "low",
70
+ last_check: null,
71
+ history: [],
72
+ retired: false,
73
+ state: "UNCHECKABLE",
74
+ // The long day count: an UNCHECKABLE promise nobody has looked at for
75
+ // months is the case this state exists to make visible.
76
+ why: "no cheap check exists — this promise is held by review, not by a runner",
77
+ distance: null,
78
+ },
79
+ {
80
+ id: "PACT-001",
81
+ statement: "Every outbound webhook is signed with the tenant's current secret.",
82
+ origin: { lane: "orc", run: "run-orc-webhooks-120726-084500", kind: "constraint" },
83
+ anchors: ["src/webhooks/sign.ts:40"],
84
+ check: { kind: "command", ref: "npm run test:webhooks" },
85
+ verified_commit: "e9dad01bb2",
86
+ confidence: "high",
87
+ last_check: { status: "pass", commit: "e9dad01bb2", at: "05-08-2026 16:02:11", ref: "npm run test:webhooks" },
88
+ history: [{ at: "05-08-2026 16:02:11", status: "pass", commit: "e9dad01bb2" }],
89
+ retired: false,
90
+ state: "HOLDING",
91
+ why: "verified at e9dad01b; no commit since has touched its anchors",
92
+ distance: 0,
93
+ },
94
+ {
95
+ id: "PACT-009",
96
+ statement: "Session cookies are always SameSite=Lax.",
97
+ origin: { lane: "orc-grill", run: "run-grill-auth-200626-113000", kind: "constraint" },
98
+ anchors: ["src/auth/session.ts"],
99
+ check: { kind: "grep", ref: "SameSite=Lax" },
100
+ verified_commit: "cc4778e0aa",
101
+ confidence: "high",
102
+ last_check: { status: "pass", commit: "cc4778e0aa", at: "21-06-2026 09:00:00", ref: "SameSite=Lax" },
103
+ history: [{ at: "21-06-2026 09:00:00", status: "pass", commit: "cc4778e0aa" }],
104
+ retired: false,
105
+ state: "HOLDING",
106
+ why: "verified at cc4778e0; no commit since has touched its anchors",
107
+ distance: 0,
108
+ },
109
+ ],
110
+ };
111
+
112
+ module.exports = { pact };
@@ -82,7 +82,7 @@ const budgetForecast = {
82
82
  fixed_roles: [
83
83
  { role: "orc-system-analyst-opus-5-high", samples: 11, p50: { input: 6100, cache_write: 41000, cache_read: 82000, output: 9000 }, p90: { input: 8600, cache_write: 58000, cache_read: 116000, output: 13000 } },
84
84
  { role: "orc-planner-opus-5-med", samples: 11, p50: { input: 5000, cache_write: 33000, cache_read: 68000, output: 7400 }, p90: { input: 7100, cache_write: 47000, cache_read: 96000, output: 10500 } },
85
- { role: "orc-trace-writer-haiku-4-5", samples: 41, p50: { input: 900, cache_write: 3000, cache_read: 5400, output: 700 }, p90: { input: 1300, cache_write: 4400, cache_read: 7800, output: 1000 } },
85
+ { role: "orc-trace-writer-haiku-5-high", samples: 41, p50: { input: 900, cache_write: 3000, cache_read: 5400, output: 700 }, p90: { input: 1300, cache_write: 4400, cache_read: 7800, output: 1000 } },
86
86
  ],
87
87
  low_confidence_bands: 1,
88
88
  min_samples: 5,
@@ -117,7 +117,7 @@ const budgetRates = {
117
117
  },
118
118
  roles: {
119
119
  "orc-system-analyst-opus-5-high": { samples: 11, p50: { input: 6100, cache_write: 41000, cache_read: 82000, output: 9000 }, p90: { input: 8600, cache_write: 58000, cache_read: 116000, output: 13000 }, peak_p50: 88000, peak_p90: 131000 },
120
- "orc-trace-writer-haiku-4-5": { samples: 41, p50: { input: 900, cache_write: 3000, cache_read: 5400, output: 700 }, p90: { input: 1300, cache_write: 4400, cache_read: 7800, output: 1000 }, peak_p50: 9000, peak_p90: 14000 },
120
+ "orc-trace-writer-haiku-5-high": { samples: 41, p50: { input: 900, cache_write: 3000, cache_read: 5400, output: 700 }, p90: { input: 1300, cache_write: 4400, cache_read: 7800, output: 1000 }, peak_p50: 9000, peak_p90: 14000 },
121
121
  },
122
122
  lanes: {},
123
123
  unattributed: { blocks: 12, tokens: { input: 900, cache_write: 12000, cache_read: 24000, output: 1100 } },
@@ -5,6 +5,8 @@
5
5
  "knowledge.graph.unknownHint": "The CLI did not answer. Run the command in a terminal to see why.",
6
6
  "knowledge.graph.off": "The code graph is off.",
7
7
  "knowledge.graph.offHint": "It is off by default. When it is on, code lanes build a local map of the code for free and keep it current.",
8
+ "knowledge.graph.semi": "semi — kept current, lanes do not read it",
9
+ "knowledge.graph.semiHint": "The graph is kept current, but no lane reads it. To enable reading, run this command:",
8
10
  "knowledge.graph.none": "The graph is on, but no index exists yet. The next code lane builds it, or press the button.",
9
11
  "knowledge.graph.files": "Files",
10
12
  "knowledge.graph.symbols": "Symbols",
@@ -5,6 +5,8 @@
5
5
  "knowledge.graph.unknownHint": "CLI tidak menjawab. Jalankan perintahnya di terminal untuk melihat penyebabnya.",
6
6
  "knowledge.graph.off": "Graf kode mati.",
7
7
  "knowledge.graph.offHint": "Default-nya mati. Jika menyala, lane kode membuat peta kode lokal secara gratis dan menjaganya tetap baru.",
8
+ "knowledge.graph.semi": "semi — selalu diperbarui, lane tidak membacanya",
9
+ "knowledge.graph.semiHint": "Graph selalu diperbarui, tetapi tidak ada lane yang membacanya. Untuk mengaktifkan pembacaan, jalankan perintah ini:",
8
10
  "knowledge.graph.none": "Graf menyala, tetapi indeksnya belum ada. Lane kode berikutnya akan membuatnya, atau tekan tombolnya.",
9
11
  "knowledge.graph.files": "File",
10
12
  "knowledge.graph.symbols": "Simbol",
@@ -149,6 +149,19 @@ function knowledgeHeaderStrip(d) {
149
149
  return strip;
150
150
  }
151
151
 
152
+ /* v2.2.0 — code_graph: semi. `graph status` answers the INDEX state, and
153
+ the API adds the configured `mode`. A semi graph is kept current but no lane
154
+ reads it, so the panel says so next to the state, with the one command that
155
+ enables reading. The mode word is a config VALUE — never translated. */
156
+ function graphSemiNote(g) {
157
+ if (!g || g.mode !== "semi") return null;
158
+ const box = el("div", "cg-semi");
159
+ const row = el("div", "row-actions");
160
+ row.append(chip("SEMI", "idle"), el("span", "note", t("knowledge.graph.semi")));
161
+ box.append(row, el("div", "note", t("knowledge.graph.semiHint")), el("pre", "cmd", "orc config set code_graph on"));
162
+ return box;
163
+ }
164
+
152
165
  /* THE CODE GRAPH CARD (v1.8.0). Every value is `orc graph status --json`'s, and
153
166
  the state word is never replaced by a friendlier synonym. An update is FREE
154
167
  (parser only, no model), so it is a button; an OFF graph shows the one config
@@ -167,6 +180,8 @@ function graphCard(g, body, gain, exact) {
167
180
  return c;
168
181
  }
169
182
  if (exact) c.append(el("div", "note", t("knowledge.cg.exact.lead")));
183
+ const semiG = graphSemiNote(g);
184
+ if (semiG && !exact) c.append(semiG);
170
185
  const head = el("div", "row-actions");
171
186
  head.append(chip(String(g.state).toUpperCase(), g.state === "fresh" ? "ok" : g.state === "drifted" ? "warn" : "idle", g.state === "drifted"));
172
187
  const upd = el("button", "btn btn-sm", "orc graph update");
@@ -1228,6 +1243,8 @@ function cgStateCard(g, body) {
1228
1243
  return c;
1229
1244
  }
1230
1245
  c.append(el("div", "note", t("knowledge.cg.state.lead")));
1246
+ const semiS = graphSemiNote(g);
1247
+ if (semiS) c.append(semiS);
1231
1248
  const ladder = el("div", "cg-ladder");
1232
1249
  const steps = [
1233
1250
  ["OFF", t("knowledge.cg.state.off"), t("knowledge.cg.state.toNone")],
@@ -0,0 +1,116 @@
1
+ # When the code graph helps (with live numbers)
2
+
3
+ Short version: **the code graph saves search work when the task must find code
4
+ or follow a change across files.** It does not help a change inside one file
5
+ that you already named. It gives no benefit until it has its data.
6
+
7
+ ---
8
+
9
+ ## 1. What the code graph does for you
10
+
11
+ The code graph is a structure index of your project: files, symbols, callers,
12
+ imports, routes and tests. The lanes read it when they plan and slice a task.
13
+ The graph hook reads it when the main session searches for a known symbol.
14
+ The key `code_graph` sets the mode: `off`, `semi` or `on`.
15
+
16
+ ---
17
+
18
+ ## 2. Before you see a benefit: the graph needs its data
19
+
20
+ > [!NOTE]
21
+ > - Run `orc graph update` ONE time first. This is a cold build. In the eval
22
+ > repo (a company Vue repo: 799 files, 8,531 symbols) it took about 3.5 s.
23
+ > With no index, every graph read answers "no index". The lane then works as
24
+ > with the graph off.
25
+ > - After that, the hooks keep the index current: after each executor, and on
26
+ > read. `orc graph status` shows `fresh`.
27
+ > - The 2.2.0 upgrade rebuilds the index one time (engine `graph@7`).
28
+ > - Notes (one sentence per function) are OPTIONAL stored knowledge. A noter
29
+ > dispatch writes them, and that dispatch costs tokens. The structure layer
30
+ > is free.
31
+
32
+ ---
33
+
34
+ ## 3. The evidence (real repo, live runs)
35
+
36
+ How we measured:
37
+
38
+ - The repo is a real company Vue 2.7 dashboard repo.
39
+ - The lane is `/orc-quick`. The main session is Opus 5.5 medium. The executor
40
+ is pinned to `orc-executor-opus-5-low`.
41
+ - Each task ran with the graph OFF and with the graph ON. The table shows
42
+ medians (or means where it says so).
43
+ - We checked each run: lint, jest, and a Playwright journey where the task has
44
+ a UI. The same grader graded each run against the same lane dossier.
45
+
46
+ | Task | What it is | Runs (OFF / ON) | Cost | Time | Tokens | Grade |
47
+ |---|---|---|---|---|---|---|
48
+ | RMT1 | Build step 1 of a new 4-step flow from a requirement document (route shell, API call, i18n, journey spec) | 5 / 3 | −9.6 % | −28.4 % | −15.8 % | equal (84) |
49
+ | RMT2 | Change one helper's signature and every caller (5 caller files, 1 test) | 3 / 3 | −2.0 % | −8.6 % | −4.2 % | equal (86) |
50
+ | RMT3 | Build step 2 on top of the built step 1 | 2 / 2 (means) | −8.9 % | +4.0 % | −14.0 % | 80 vs 85 (one ON run missed a display detail) |
51
+ | RMT4 | Change behaviour across the built step 1 + step 2 page; ON had stored notes | 2 / 2 (means) | +7.7 % | +45.5 % | +4.4 % | 77 vs 85.5 (one ON run 66 for stray git-hook files, the other 88) |
52
+
53
+ e2e: every RMT1/RMT3/RMT4 run that passed reached every journey step in both
54
+ arms.
55
+
56
+ N = 2–5 per arm. A difference under about 10 % is inside the run-to-run noise
57
+ of one task.
58
+
59
+ ---
60
+
61
+ ## 4. Where the graph helps
62
+
63
+ - **Finding the code to copy or to change.** The executor's exploration fell
64
+ 40–74 % (RMT1, RMT3 phase split).
65
+ - **Changes that ripple across files.** Callers, props / emits, routes and the
66
+ tests that reach a caller come in one card. This card replaces a grep, a
67
+ test hunt and a coverage check.
68
+ - **The main session's own search.** The hook answers a search for a known
69
+ symbol with its callers, tests and coverage (one time per name, 3 per run at
70
+ most). When an executor returns, the hook gives the affected tests.
71
+ - **Time.** The clearest win is on new-feature work (RMT1 −28 %).
72
+
73
+ ---
74
+
75
+ ## 5. Where it does not help (or helps very little)
76
+
77
+ RMT4 is the live example. It is a small follow-up change inside a page that
78
+ the agent reads in a few calls. There was no gain, also with stored notes.
79
+
80
+ - **A change inside ONE named file with no outside effect.** Both arms read
81
+ that file. ORC skips the anchors.
82
+ - **Very small tasks.** The lane's own overhead (config, trace, questions) is
83
+ most of the cost. The graph is break-even.
84
+ - **Test writing and coverage work.** The graph does not write tests. A
85
+ project rule such as "> 90 % branch coverage" can cost more than all that the
86
+ graph saves. We saw this in both arms.
87
+ - **No index, or a stale index.** The lane falls back to Grep. There is no
88
+ harm and no gain.
89
+
90
+ ---
91
+
92
+ ## 6. Turn it on
93
+
94
+ ```bash
95
+ orc config set code_graph on
96
+ orc graph update
97
+ ```
98
+
99
+ Run `orc graph update` one time. The modes are:
100
+
101
+ - `on` — the hooks keep the graph current, and the lanes read it.
102
+ - `semi` — the hooks keep the graph current. No lane reads it.
103
+ - `off` — nothing.
104
+
105
+ For the other keys (`code_graph_notes`, `code_graph_card_budget` and more),
106
+ see [configuration](configuration.md).
107
+
108
+ ---
109
+
110
+ ## 7. What it costs
111
+
112
+ - **Structure:** zero tokens. Local files under `.claude/orc/graph/`. No
113
+ background process.
114
+ - **Cards:** a few hundred tokens each, with a cap.
115
+ - **Hook cards:** 3 per run at most in the main session.
116
+ - **Notes:** optional. Each batch costs a noter dispatch.