@otto-code/brain 0.7.5

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 (150) hide show
  1. package/bin/otto-brain +2 -0
  2. package/dist/bench/context-corpus.d.ts +58 -0
  3. package/dist/bench/context-corpus.js +210 -0
  4. package/dist/bench/corpus.d.ts +31 -0
  5. package/dist/bench/corpus.js +379 -0
  6. package/dist/bench/curated-repos.d.ts +35 -0
  7. package/dist/bench/curated-repos.js +41 -0
  8. package/dist/bench/health.d.ts +50 -0
  9. package/dist/bench/health.js +112 -0
  10. package/dist/bench/index.d.ts +103 -0
  11. package/dist/bench/index.js +209 -0
  12. package/dist/bench/mine.d.ts +32 -0
  13. package/dist/bench/mine.js +101 -0
  14. package/dist/bench/repo-task.d.ts +93 -0
  15. package/dist/bench/repo-task.js +380 -0
  16. package/dist/bench/repo.d.ts +125 -0
  17. package/dist/bench/repo.js +195 -0
  18. package/dist/bench/rescore.d.ts +41 -0
  19. package/dist/bench/rescore.js +127 -0
  20. package/dist/bench/tasks.d.ts +124 -0
  21. package/dist/bench/tasks.js +1249 -0
  22. package/dist/bench/verify.d.ts +142 -0
  23. package/dist/bench/verify.js +350 -0
  24. package/dist/cli.d.ts +13 -0
  25. package/dist/cli.js +72 -0
  26. package/dist/commands/bench.d.ts +20 -0
  27. package/dist/commands/bench.js +222 -0
  28. package/dist/commands/calibrate.d.ts +19 -0
  29. package/dist/commands/calibrate.js +75 -0
  30. package/dist/commands/catalog.d.ts +32 -0
  31. package/dist/commands/catalog.js +48 -0
  32. package/dist/commands/config.d.ts +13 -0
  33. package/dist/commands/config.js +90 -0
  34. package/dist/commands/lifecycle.d.ts +29 -0
  35. package/dist/commands/lifecycle.js +194 -0
  36. package/dist/commands/pull.d.ts +22 -0
  37. package/dist/commands/pull.js +135 -0
  38. package/dist/commands/report.d.ts +10 -0
  39. package/dist/commands/report.js +34 -0
  40. package/dist/commands/rescore.d.ts +11 -0
  41. package/dist/commands/rescore.js +48 -0
  42. package/dist/commands/runtime.d.ts +21 -0
  43. package/dist/commands/runtime.js +62 -0
  44. package/dist/commands/scan.d.ts +24 -0
  45. package/dist/commands/scan.js +55 -0
  46. package/dist/commands/search.d.ts +31 -0
  47. package/dist/commands/search.js +135 -0
  48. package/dist/commands/share.d.ts +26 -0
  49. package/dist/commands/share.js +148 -0
  50. package/dist/commands/sweep.d.ts +21 -0
  51. package/dist/commands/sweep.js +69 -0
  52. package/dist/commands/ui.d.ts +9 -0
  53. package/dist/commands/ui.js +28 -0
  54. package/dist/config/env.d.ts +10 -0
  55. package/dist/config/env.js +48 -0
  56. package/dist/config/index.d.ts +9 -0
  57. package/dist/config/index.js +9 -0
  58. package/dist/config/otto-home.d.ts +2 -0
  59. package/dist/config/otto-home.js +24 -0
  60. package/dist/config/paths.d.ts +20 -0
  61. package/dist/config/paths.js +33 -0
  62. package/dist/config/private-files.d.ts +3 -0
  63. package/dist/config/private-files.js +32 -0
  64. package/dist/config/profiles.d.ts +34 -0
  65. package/dist/config/profiles.js +116 -0
  66. package/dist/config/schema.d.ts +1035 -0
  67. package/dist/config/schema.js +191 -0
  68. package/dist/config/store.d.ts +11 -0
  69. package/dist/config/store.js +73 -0
  70. package/dist/gguf.d.ts +61 -0
  71. package/dist/gguf.js +231 -0
  72. package/dist/gpu.d.ts +12 -0
  73. package/dist/gpu.js +49 -0
  74. package/dist/index.d.ts +14 -0
  75. package/dist/index.js +13 -0
  76. package/dist/main.d.ts +2 -0
  77. package/dist/main.js +5 -0
  78. package/dist/models/dirs.d.ts +9 -0
  79. package/dist/models/dirs.js +21 -0
  80. package/dist/models/download.d.ts +31 -0
  81. package/dist/models/download.js +105 -0
  82. package/dist/models/enrich.d.ts +36 -0
  83. package/dist/models/enrich.js +68 -0
  84. package/dist/models/hf.d.ts +62 -0
  85. package/dist/models/hf.js +114 -0
  86. package/dist/models/index.d.ts +15 -0
  87. package/dist/models/index.js +49 -0
  88. package/dist/models/manage.d.ts +27 -0
  89. package/dist/models/manage.js +112 -0
  90. package/dist/models/pick.d.ts +3 -0
  91. package/dist/models/pick.js +36 -0
  92. package/dist/models/scan.d.ts +13 -0
  93. package/dist/models/scan.js +185 -0
  94. package/dist/ops/archive.d.ts +34 -0
  95. package/dist/ops/archive.js +105 -0
  96. package/dist/ops/calibrate.d.ts +49 -0
  97. package/dist/ops/calibrate.js +74 -0
  98. package/dist/ops/report.d.ts +26 -0
  99. package/dist/ops/report.js +532 -0
  100. package/dist/ops/results.d.ts +207 -0
  101. package/dist/ops/results.js +250 -0
  102. package/dist/ops/sweep.d.ts +77 -0
  103. package/dist/ops/sweep.js +126 -0
  104. package/dist/output/index.d.ts +5 -0
  105. package/dist/output/index.js +5 -0
  106. package/dist/output/render.d.ts +4 -0
  107. package/dist/output/render.js +96 -0
  108. package/dist/output/types.d.ts +52 -0
  109. package/dist/output/types.js +9 -0
  110. package/dist/output/with-output.d.ts +3 -0
  111. package/dist/output/with-output.js +42 -0
  112. package/dist/run.d.ts +5 -0
  113. package/dist/run.js +19 -0
  114. package/dist/runtime/args.d.ts +21 -0
  115. package/dist/runtime/args.js +71 -0
  116. package/dist/runtime/index.d.ts +13 -0
  117. package/dist/runtime/index.js +41 -0
  118. package/dist/runtime/lmstudio.d.ts +10 -0
  119. package/dist/runtime/lmstudio.js +88 -0
  120. package/dist/runtime/managed.d.ts +26 -0
  121. package/dist/runtime/managed.js +148 -0
  122. package/dist/service/model-selector.d.ts +36 -0
  123. package/dist/service/model-selector.js +123 -0
  124. package/dist/service/pid-lock.d.ts +18 -0
  125. package/dist/service/pid-lock.js +50 -0
  126. package/dist/service/router.d.ts +144 -0
  127. package/dist/service/router.js +746 -0
  128. package/dist/service/scheduler.d.ts +74 -0
  129. package/dist/service/scheduler.js +110 -0
  130. package/dist/service/serve.d.ts +41 -0
  131. package/dist/service/serve.js +278 -0
  132. package/dist/service/supervisor.d.ts +67 -0
  133. package/dist/service/supervisor.js +222 -0
  134. package/dist/service/tailscale.d.ts +19 -0
  135. package/dist/service/tailscale.js +62 -0
  136. package/dist/service/tls.d.ts +77 -0
  137. package/dist/service/tls.js +192 -0
  138. package/dist/sysmon.d.ts +50 -0
  139. package/dist/sysmon.js +103 -0
  140. package/dist/tui/app.d.ts +208 -0
  141. package/dist/tui/app.js +1801 -0
  142. package/dist/tui/screen.d.ts +72 -0
  143. package/dist/tui/screen.js +176 -0
  144. package/dist/types.d.ts +76 -0
  145. package/dist/types.js +7 -0
  146. package/dist/version.d.ts +2 -0
  147. package/dist/version.js +8 -0
  148. package/dist/vram.d.ts +67 -0
  149. package/dist/vram.js +132 -0
  150. package/package.json +58 -0
package/bin/otto-brain ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import "../dist/main.js";
@@ -0,0 +1,58 @@
1
+ /**
2
+ * A window-sized synthetic codebase for the `context-stress` benchmark task.
3
+ *
4
+ * The point of this task is the opposite of a clever puzzle: it is a *volume*
5
+ * test. A staged pipeline has N modules, each of which returns its input
6
+ * unchanged (a placeholder). The real rule each stage must implement -- an
7
+ * operation and an operand -- lives ONLY in the specification, which is split
8
+ * across `docs/spec/part_XX.md` and generated verbose enough to fill a target
9
+ * fraction of the model's context window. So the model cannot fix any stage
10
+ * without reading the spec, and it cannot fix ALL of them without holding most
11
+ * of the window at once.
12
+ *
13
+ * That is the design guarantee: a run that scores well on the hidden per-stage
14
+ * oracle MUST have held (read and kept in context) at least the target fraction
15
+ * of the window. A run that shortcuts scores low AND shows low held context --
16
+ * which is exactly the signal a 1-2%-held long-horizon task fails to give.
17
+ *
18
+ * Everything here is deterministic (seeded by stage index, never `Math.random`)
19
+ * so the corpus, the reference fix, and the oracle all agree across runs. All
20
+ * arithmetic is bounded mod 1000 so the JavaScript-computed expectations match
21
+ * Python's integer semantics exactly (no bignum drift through a long pipeline).
22
+ */
23
+ /** One stage's fully-resolved rule: the op, its operand, and a probe/expected. */
24
+ export interface StageSpec {
25
+ index: number;
26
+ op: "add" | "mul" | "shift";
27
+ operand: number;
28
+ /** A small fixed probe input for this stage's oracle test. */
29
+ sample: number;
30
+ /** The correct `apply(sample)`, computed here so the oracle is self-consistent. */
31
+ expected: number;
32
+ }
33
+ /** The generated corpus: what the model sees, the hidden oracle, and the fix. */
34
+ export interface ContextCorpus {
35
+ /** Files shown to the model: docs (read-only) + buggy Python modules. */
36
+ files: Record<string, string>;
37
+ /** The correct Python modules, kept ONLY for the unit test's oracle check. */
38
+ reference: Record<string, string>;
39
+ /** The hidden per-stage oracle (`test_pipeline.py`), never shown to the model. */
40
+ hiddenTest: string;
41
+ /** Basenames of the runnable Python modules (no docs), for the test harness. */
42
+ pyFiles: string[];
43
+ /** The spec doc paths, in order. */
44
+ specFiles: string[];
45
+ /** The resolved stage rules. */
46
+ stages: StageSpec[];
47
+ /** The approximate character budget the docs were padded to. */
48
+ docChars: number;
49
+ }
50
+ /**
51
+ * Generate a window-sized staged-pipeline corpus whose spec fills roughly
52
+ * `targetTokens` (estimated at ~4 chars/token). Returns the buggy corpus the
53
+ * model works on, the reference fix, and the hidden oracle.
54
+ */
55
+ export declare function generateContextCorpus({ targetTokens }: {
56
+ targetTokens: number;
57
+ }): ContextCorpus;
58
+ //# sourceMappingURL=context-corpus.d.ts.map
@@ -0,0 +1,210 @@
1
+ /**
2
+ * A window-sized synthetic codebase for the `context-stress` benchmark task.
3
+ *
4
+ * The point of this task is the opposite of a clever puzzle: it is a *volume*
5
+ * test. A staged pipeline has N modules, each of which returns its input
6
+ * unchanged (a placeholder). The real rule each stage must implement -- an
7
+ * operation and an operand -- lives ONLY in the specification, which is split
8
+ * across `docs/spec/part_XX.md` and generated verbose enough to fill a target
9
+ * fraction of the model's context window. So the model cannot fix any stage
10
+ * without reading the spec, and it cannot fix ALL of them without holding most
11
+ * of the window at once.
12
+ *
13
+ * That is the design guarantee: a run that scores well on the hidden per-stage
14
+ * oracle MUST have held (read and kept in context) at least the target fraction
15
+ * of the window. A run that shortcuts scores low AND shows low held context --
16
+ * which is exactly the signal a 1-2%-held long-horizon task fails to give.
17
+ *
18
+ * Everything here is deterministic (seeded by stage index, never `Math.random`)
19
+ * so the corpus, the reference fix, and the oracle all agree across runs. All
20
+ * arithmetic is bounded mod 1000 so the JavaScript-computed expectations match
21
+ * Python's integer semantics exactly (no bignum drift through a long pipeline).
22
+ */
23
+ /** Neutral spec-prose filler, used to pad each part to its character budget so
24
+ * the corpus reaches the target window fraction. Deterministic by index. */
25
+ const FILLER = [
26
+ "This constraint is load-bearing: downstream stages assume the transform has already been applied, so skipping it silently corrupts every later result.",
27
+ "The operand was chosen during calibration and must not be inferred from the code, which deliberately carries no hint of its value.",
28
+ "Reviewers should treat this section as normative; where the prose and a placeholder disagree, the prose wins.",
29
+ "Historically this rule lived in the module itself, but colocating it with the code led to drift, so it was moved here and the code reset to a passthrough.",
30
+ "Note that the ordering of stages is significant only through the running total; each stage's own rule is independent of its neighbours.",
31
+ "A conforming implementation returns an integer in the range produced by the bounded arithmetic described below, never a float.",
32
+ "The specification is intentionally verbose so that a reader must carry it in working memory rather than pattern-matching a single line.",
33
+ "When in doubt, re-read the operand: transcription errors here are the most common cause of a failing stage.",
34
+ ];
35
+ function operandFor(index) {
36
+ // Knuth multiplicative hash, kept well under 2^53 for any realistic N, mapped
37
+ // to a readable 3-digit operand so the spec prose can name it plainly.
38
+ return 100 + ((index * 2654435761) % 900);
39
+ }
40
+ function opFor(index) {
41
+ return ["add", "mul", "shift"][index % 3];
42
+ }
43
+ /** Apply a stage's rule, bounded mod 1000 (matches the generated Python). */
44
+ function applyRule(op, operand, x) {
45
+ if (op === "mul")
46
+ return (x * operand) % 1000;
47
+ if (op === "shift")
48
+ return (x + operand * 2) % 1000;
49
+ return (x + operand) % 1000;
50
+ }
51
+ /** The Python expression body for a stage's correct `apply`, matching applyRule. */
52
+ function pyExpr(op, operand) {
53
+ if (op === "mul")
54
+ return `(x * ${operand}) % 1000`;
55
+ if (op === "shift")
56
+ return `(x + ${operand * 2}) % 1000`;
57
+ return `(x + ${operand}) % 1000`;
58
+ }
59
+ /** A human-readable rule description for the spec prose. */
60
+ function ruleProse(op, operand) {
61
+ if (op === "mul")
62
+ return `multiply the running value by operand **${operand}**, then take the result modulo 1000`;
63
+ if (op === "shift")
64
+ return `add **twice** operand ${operand} (that is, ${operand * 2}) to the running value, then take the result modulo 1000`;
65
+ return `add operand **${operand}** to the running value, then take the result modulo 1000`;
66
+ }
67
+ function stageModuleName(index) {
68
+ return `stage_${String(index).padStart(2, "0")}`;
69
+ }
70
+ function buggyStage(index) {
71
+ const name = stageModuleName(index);
72
+ return (`"""${name}: one stage of the pipeline.\n\n` +
73
+ `This module is a PLACEHOLDER. It must apply the rule documented for stage ` +
74
+ `${index} in the specification under docs/spec/. Until then it returns its\n` +
75
+ `input unchanged, which the oracle test for this stage will reject.\n"""\n\n\n` +
76
+ `def apply(x):\n` +
77
+ ` # TODO: implement stage ${index} per docs/spec/.\n` +
78
+ ` return x\n`);
79
+ }
80
+ function referenceStage(index, op, operand) {
81
+ const name = stageModuleName(index);
82
+ return (`"""${name}: one stage of the pipeline (reference implementation)."""\n\n\n` +
83
+ `def apply(x):\n` +
84
+ ` return ${pyExpr(op, operand)}\n`);
85
+ }
86
+ function pipelineModule(count) {
87
+ const names = Array.from({ length: count }, (_, i) => stageModuleName(i));
88
+ const imports = names.map((n) => `import ${n}`).join("\n");
89
+ const list = names.join(", ");
90
+ return (`"""The staged pipeline. Applies every stage's apply() in order.\n\n` +
91
+ `Each stage is implemented in its own module; the rules live in docs/spec/.\n"""\n` +
92
+ `${imports}\n\n` +
93
+ `STAGES = [${list}]\n\n\n` +
94
+ `def run(x):\n` +
95
+ ` total = x\n` +
96
+ ` for stage in STAGES:\n` +
97
+ ` total = stage.apply(total)\n` +
98
+ ` return total\n`);
99
+ }
100
+ const PIPELINE_START = 5;
101
+ function endToEnd(stages) {
102
+ let total = PIPELINE_START;
103
+ for (const s of stages)
104
+ total = applyRule(s.op, s.operand, total);
105
+ return total;
106
+ }
107
+ function hiddenTest(stages) {
108
+ const imports = stages.map((s) => `import ${stageModuleName(s.index)}`).join("\n");
109
+ const perStage = stages
110
+ .map((s) => ` def test_${stageModuleName(s.index)}(self):\n` +
111
+ ` self.assertEqual(${stageModuleName(s.index)}.apply(${s.sample}), ${s.expected})\n`)
112
+ .join("\n");
113
+ const final = endToEnd(stages);
114
+ return (`import unittest\n\n` +
115
+ `${imports}\n` +
116
+ `import pipeline\n\n\n` +
117
+ `class TestPipeline(unittest.TestCase):\n` +
118
+ `${perStage}\n` +
119
+ ` def test_pipeline_end_to_end(self):\n` +
120
+ ` self.assertEqual(pipeline.run(${PIPELINE_START}), ${final})\n\n\n` +
121
+ `if __name__ == "__main__":\n` +
122
+ ` unittest.main()\n`);
123
+ }
124
+ /** Pad `body` with deterministic filler prose until it reaches `budgetChars`. */
125
+ function padTo(body, budgetChars, seed) {
126
+ let out = body;
127
+ let i = seed;
128
+ while (out.length < budgetChars) {
129
+ out += `\n\n${FILLER[i % FILLER.length]}`;
130
+ i += 1;
131
+ }
132
+ return out;
133
+ }
134
+ /** Build one spec part covering `stages`, padded to `budgetChars`. */
135
+ function specPart(partIndex, stages, budgetChars) {
136
+ const heading = `# Pipeline specification — part ${String(partIndex).padStart(2, "0")}\n\n` +
137
+ `This part defines the rule for stages ${stages[0].index}–${stages[stages.length - 1].index}. ` +
138
+ `Each stage's module in the working copy is a passthrough placeholder; implement its \`apply(x)\` ` +
139
+ `exactly as written here. All arithmetic is bounded modulo 1000 and returns an integer.\n`;
140
+ const entries = stages
141
+ .map((s) => `\n## Stage ${s.index}\n\n` +
142
+ `Module: \`${stageModuleName(s.index)}.py\`. Rule: ${ruleProse(s.op, s.operand)}. ` +
143
+ `Equivalently, \`apply(x)\` must return \`${pyExpr(s.op, s.operand)}\`.\n`)
144
+ .join("");
145
+ return padTo(heading + entries, budgetChars, partIndex * 31 + stages[0].index);
146
+ }
147
+ /**
148
+ * Generate a window-sized staged-pipeline corpus whose spec fills roughly
149
+ * `targetTokens` (estimated at ~4 chars/token). Returns the buggy corpus the
150
+ * model works on, the reference fix, and the hidden oracle.
151
+ */
152
+ export function generateContextCorpus({ targetTokens }) {
153
+ // ~3000 tokens of spec per stage keeps the stage count sane while letting the
154
+ // docs carry the volume; clamp so tiny windows still get a real pipeline and
155
+ // huge windows do not generate an unbounded number of modules.
156
+ const stageCount = Math.max(12, Math.min(48, Math.round(targetTokens / 3000)));
157
+ const docChars = Math.max(2000, targetTokens * 4);
158
+ const stages = Array.from({ length: stageCount }, (_, index) => {
159
+ const op = opFor(index);
160
+ const operand = operandFor(index);
161
+ const sample = 3 + (index % 7);
162
+ return { index, op, operand, sample, expected: applyRule(op, operand, sample) };
163
+ });
164
+ // Split stages across doc parts (~6 per part), each padded to an equal share
165
+ // of the doc budget so the whole spec sums to ~docChars.
166
+ const partCount = Math.min(stageCount, Math.max(3, Math.round(stageCount / 6)));
167
+ const perPartBudget = Math.floor(docChars / partCount);
168
+ const partStride = Math.ceil(stageCount / partCount);
169
+ const files = {};
170
+ const reference = {};
171
+ const specFiles = [];
172
+ files["README.md"] =
173
+ "# staged-pipeline\n\nA numeric pipeline built from independent stages. Every stage " +
174
+ "module under the working root is a placeholder that returns its input unchanged; the " +
175
+ "rule each one must implement is specified in `docs/spec/`. Fix every stage, then run " +
176
+ "`python -m unittest test_pipeline`.\n";
177
+ files["docs/OVERVIEW.md"] =
178
+ "# Specification overview\n\nThe pipeline applies each stage's `apply(x)` in order, starting " +
179
+ `from ${PIPELINE_START}. There are ${stageCount} stages. The rule for each stage — its ` +
180
+ "operation and operand — is defined in the numbered parts under `docs/spec/`. The code carries " +
181
+ "no hint of the operands; you must read the spec.\n";
182
+ for (let p = 0; p < partCount; p += 1) {
183
+ const slice = stages.slice(p * partStride, (p + 1) * partStride);
184
+ if (!slice.length)
185
+ continue;
186
+ const path = `docs/spec/part_${String(p).padStart(2, "0")}.md`;
187
+ files[path] = specPart(p, slice, perPartBudget);
188
+ specFiles.push(path);
189
+ }
190
+ const pyFiles = [];
191
+ for (const s of stages) {
192
+ const file = `${stageModuleName(s.index)}.py`;
193
+ files[file] = buggyStage(s.index);
194
+ reference[file] = referenceStage(s.index, s.op, s.operand);
195
+ pyFiles.push(file);
196
+ }
197
+ files["pipeline.py"] = pipelineModule(stageCount);
198
+ reference["pipeline.py"] = files["pipeline.py"];
199
+ pyFiles.push("pipeline.py");
200
+ return {
201
+ files,
202
+ reference,
203
+ hiddenTest: hiddenTest(stages),
204
+ pyFiles,
205
+ specFiles,
206
+ stages,
207
+ docChars,
208
+ };
209
+ }
210
+ //# sourceMappingURL=context-corpus.js.map
@@ -0,0 +1,31 @@
1
+ /**
2
+ * A self-contained codebase for the extra-long-horizon benchmark task.
3
+ *
4
+ * The bug in `pricing.py` cannot be fixed correctly by reading the code alone:
5
+ * the two rules the fix must honour (discounts apply to the ORIGINAL subtotal,
6
+ * and the combined discount is capped at 50%) live only in `docs/SPEC.md`. So a
7
+ * model has to explore the tree, find and read the spec, and only then produce a
8
+ * fix that passes the hidden oracle. Reading widely is the point - it is what
9
+ * fills context on a long-horizon task.
10
+ *
11
+ * The markdown is deliberately verbose: the more a model reads to locate the two
12
+ * load-bearing rules, the more of its context window it fills, which the task
13
+ * reports. Expand the corpus to push the context bar higher.
14
+ */
15
+ /** The reference fix, kept only so the task's own unit test can sanity-check the
16
+ * oracle. Never shown to the model. */
17
+ export declare const PRICING_PY_REFERENCE = "\"\"\"Order pricing: apply discount rules to a subtotal.\"\"\"\nfrom rules import PercentRule # noqa: F401\n\n\ndef compute_total(subtotal_cents, rules):\n ordered = sorted(rules, key=lambda r: r.priority, reverse=True)\n discount = 0\n for rule in ordered:\n discount += rule.discount(subtotal_cents)\n cap = subtotal_cents // 2\n if discount > cap:\n discount = cap\n return subtotal_cents - discount\n";
18
+ /** The hidden oracle - never shown to the model, written only at test time. Its
19
+ * expectations encode docs/SPEC.md exactly. */
20
+ export declare const EXTRA_HIDDEN_TEST = "import unittest\n\nfrom pricing import compute_total\nfrom rules import PercentRule, FixedRule\n\n\nclass TestPricing(unittest.TestCase):\n def test_empty_rules(self):\n self.assertEqual(compute_total(10000, []), 10000)\n\n def test_single_percent(self):\n self.assertEqual(compute_total(10000, [PercentRule(\"a\", 20)]), 8000)\n\n def test_two_rules_do_not_compound(self):\n # 30% + 40% of the ORIGINAL 10000 = 3000 + 4000 = 7000, capped at 5000.\n rules = [PercentRule(\"a\", 30), PercentRule(\"b\", 40)]\n self.assertEqual(compute_total(10000, rules), 5000)\n\n def test_combined_cap(self):\n # A single 60% rule is capped at 50%.\n self.assertEqual(compute_total(10000, [PercentRule(\"big\", 60)]), 5000)\n\n def test_under_cap(self):\n # 10% + 15% = 2500 discount, below the cap.\n rules = [PercentRule(\"a\", 10), PercentRule(\"b\", 15)]\n self.assertEqual(compute_total(10000, rules), 7500)\n\n def test_fixed_and_percent_capped(self):\n # 4000 fixed + 30% (3000) = 7000, capped at 5000.\n rules = [FixedRule(\"f\", 4000), PercentRule(\"p\", 30)]\n self.assertEqual(compute_total(10000, rules), 5000)\n\n\nif __name__ == \"__main__\":\n unittest.main()\n";
21
+ /**
22
+ * The files the model can see and explore. Python modules are the working copy it
23
+ * edits; markdown is read-only reference. The hidden test is intentionally NOT
24
+ * here.
25
+ */
26
+ export declare const EXTRA_CORPUS: Record<string, string>;
27
+ /** The Python modules that make up the runnable working copy (no docs). */
28
+ export declare const EXTRA_PY_FILES: string[];
29
+ /** The one file the model is meant to fix. */
30
+ export declare const EXTRA_TARGET_FILE = "pricing.py";
31
+ //# sourceMappingURL=corpus.d.ts.map
@@ -0,0 +1,379 @@
1
+ /**
2
+ * A self-contained codebase for the extra-long-horizon benchmark task.
3
+ *
4
+ * The bug in `pricing.py` cannot be fixed correctly by reading the code alone:
5
+ * the two rules the fix must honour (discounts apply to the ORIGINAL subtotal,
6
+ * and the combined discount is capped at 50%) live only in `docs/SPEC.md`. So a
7
+ * model has to explore the tree, find and read the spec, and only then produce a
8
+ * fix that passes the hidden oracle. Reading widely is the point - it is what
9
+ * fills context on a long-horizon task.
10
+ *
11
+ * The markdown is deliberately verbose: the more a model reads to locate the two
12
+ * load-bearing rules, the more of its context window it fills, which the task
13
+ * reports. Expand the corpus to push the context bar higher.
14
+ */
15
+ /** The buggy engine the model must fix. Applies discounts to the RUNNING total
16
+ * (so they compound) and never caps them - both wrong per docs/SPEC.md. */
17
+ const PRICING_PY = `"""Order pricing: apply discount rules to a subtotal.
18
+
19
+ See docs/SPEC.md for the discount rules this module is supposed to implement, and
20
+ docs/ARCHITECTURE.md for how it fits with rules.py and money.py.
21
+ """
22
+ from rules import PercentRule # noqa: F401 (re-exported for callers)
23
+
24
+
25
+ def compute_total(subtotal_cents, rules):
26
+ """Return the order total in cents after applying every discount rule.
27
+
28
+ subtotal_cents: the pre-discount total, in integer cents.
29
+ rules: a list of rule objects, each with a .discount(amount_cents) method.
30
+ """
31
+ total = subtotal_cents
32
+ for rule in rules:
33
+ total -= rule.discount(total)
34
+ return total
35
+ `;
36
+ /** The reference fix, kept only so the task's own unit test can sanity-check the
37
+ * oracle. Never shown to the model. */
38
+ export const PRICING_PY_REFERENCE = `"""Order pricing: apply discount rules to a subtotal."""
39
+ from rules import PercentRule # noqa: F401
40
+
41
+
42
+ def compute_total(subtotal_cents, rules):
43
+ ordered = sorted(rules, key=lambda r: r.priority, reverse=True)
44
+ discount = 0
45
+ for rule in ordered:
46
+ discount += rule.discount(subtotal_cents)
47
+ cap = subtotal_cents // 2
48
+ if discount > cap:
49
+ discount = cap
50
+ return subtotal_cents - discount
51
+ `;
52
+ const RULES_PY = `"""Discount rule types.
53
+
54
+ A rule exposes .discount(amount_cents) -> int and a .priority (higher runs
55
+ first, per docs/SPEC.md "Ordering"). Discounts are integer cents; fractional
56
+ cents are floored, matching money.floor_cents.
57
+ """
58
+
59
+
60
+ class PercentRule:
61
+ """A flat percentage off the amount it is given."""
62
+
63
+ def __init__(self, name, percent, priority=0):
64
+ self.name = name
65
+ self.percent = percent
66
+ self.priority = priority
67
+
68
+ def discount(self, amount_cents):
69
+ return amount_cents * self.percent // 100
70
+
71
+
72
+ class FixedRule:
73
+ """A fixed number of cents off, never more than the amount."""
74
+
75
+ def __init__(self, name, cents, priority=0):
76
+ self.name = name
77
+ self.cents = cents
78
+ self.priority = priority
79
+
80
+ def discount(self, amount_cents):
81
+ return min(self.cents, amount_cents)
82
+ `;
83
+ const MONEY_PY = `"""Money helpers. All amounts are integer cents; never use floats for money.
84
+
85
+ docs/SPEC.md "Rounding" governs how any ratio is turned back into cents.
86
+ """
87
+
88
+
89
+ def to_cents(dollars):
90
+ return int(round(dollars * 100))
91
+
92
+
93
+ def floor_cents(amount_cents):
94
+ return int(amount_cents)
95
+
96
+
97
+ def format_money(amount_cents):
98
+ return "$%d.%02d" % (amount_cents // 100, amount_cents % 100)
99
+ `;
100
+ const MODELS_PY = `"""Cart and line-item value objects. The pricing engine works on the cart's
101
+ subtotal (see cart_subtotal), not on individual lines.
102
+ """
103
+
104
+
105
+ class LineItem:
106
+ def __init__(self, sku, unit_cents, quantity):
107
+ self.sku = sku
108
+ self.unit_cents = unit_cents
109
+ self.quantity = quantity
110
+
111
+ def line_total(self):
112
+ return self.unit_cents * self.quantity
113
+
114
+
115
+ class Cart:
116
+ def __init__(self, items=None):
117
+ self.items = items or []
118
+
119
+ def add(self, item):
120
+ self.items.append(item)
121
+
122
+ def subtotal(self):
123
+ return sum(item.line_total() for item in self.items)
124
+
125
+
126
+ def cart_subtotal(cart):
127
+ return cart.subtotal()
128
+ `;
129
+ const CATALOG_PY = `"""A tiny in-memory product catalog. Not used by the pricing math, but the
130
+ handlers look products up here before building a cart.
131
+ """
132
+
133
+ CATALOG = {
134
+ "BOOK-01": 1999,
135
+ "MUG-07": 1250,
136
+ "PEN-42": 399,
137
+ "DESK-99": 18900,
138
+ }
139
+
140
+
141
+ def price_of(sku):
142
+ return CATALOG.get(sku)
143
+
144
+
145
+ def known_skus():
146
+ return sorted(CATALOG)
147
+ `;
148
+ const README_MD = `# orderkit
149
+
150
+ A small order-pricing library. An order's total is its cart subtotal with a set
151
+ of discount **rules** applied.
152
+
153
+ ## Where things live
154
+
155
+ - \`pricing.py\` - the engine: \`compute_total(subtotal_cents, rules)\`.
156
+ - \`rules.py\` - the rule types (\`PercentRule\`, \`FixedRule\`).
157
+ - \`money.py\` - integer-cents money helpers.
158
+ - \`models.py\` - \`Cart\` / \`LineItem\`.
159
+ - \`catalog.py\` - a demo product catalog.
160
+ - \`docs/SPEC.md\` - **the authoritative pricing rules.** If the code and the
161
+ spec disagree, the spec is right and the code is a bug.
162
+ - \`docs/ARCHITECTURE.md\` - how the modules fit together.
163
+ - \`docs/CHANGELOG.md\` - what changed and when.
164
+
165
+ ## Running the tests
166
+
167
+ \`python -m unittest test_pricing\`
168
+
169
+ If a test fails, read \`docs/SPEC.md\` before changing the math - the intended
170
+ behaviour is defined there, not inferable from the current code.
171
+ `;
172
+ const SPEC_MD = `# Pricing specification
173
+
174
+ This document is authoritative. \`pricing.py\` must implement exactly what is
175
+ written here; where the code differs, the code is wrong.
176
+
177
+ ## Inputs
178
+
179
+ \`compute_total(subtotal_cents, rules)\` receives:
180
+
181
+ - \`subtotal_cents\`: the pre-discount order total, a non-negative integer in
182
+ cents.
183
+ - \`rules\`: a list of discount rules, each exposing \`discount(amount_cents)\`
184
+ and an integer \`priority\`.
185
+
186
+ It returns the final total in cents, a non-negative integer.
187
+
188
+ ## Rule application
189
+
190
+ ### Ordering
191
+
192
+ Rules are applied in **descending priority** (highest \`priority\` first). Two
193
+ rules with equal priority may be applied in any order; the specification is
194
+ written so that the result does not depend on the order of equal-priority rules.
195
+
196
+ ### Base amount — the load-bearing rule
197
+
198
+ Every rule's discount is computed against the **original subtotal**, NOT against
199
+ the running total after earlier rules. Discounts do **not** compound. A 30% rule
200
+ and a 40% rule on a $100.00 order remove \`$30.00 + $40.00 = $70.00\`, they do
201
+ **not** remove 30% and then 40% of what remains ($58.00 off).
202
+
203
+ This is the single most common mistake when re-implementing the engine: applying
204
+ each discount to the amount left by the previous one. Do not do that.
205
+
206
+ ### Combined cap — the other load-bearing rule
207
+
208
+ The **sum** of all rule discounts is capped at **50% of the original subtotal**.
209
+ Once the accumulated discount reaches half the subtotal, no further discount is
210
+ applied. So \`$30.00 + $40.00 = $70.00\` of discount on a $100.00 order is capped
211
+ to \`$50.00\`, giving a total of \`$50.00\`, never \`$30.00\`.
212
+
213
+ The cap is on the *combined* discount, applied after summing every rule, not per
214
+ rule.
215
+
216
+ ## Result
217
+
218
+ \`total = subtotal_cents - min(sum_of_discounts, subtotal_cents // 2)\`
219
+
220
+ The total is therefore always between 50% and 100% of the subtotal, inclusive,
221
+ and is a non-negative integer number of cents.
222
+
223
+ ## Rounding
224
+
225
+ All arithmetic is in integer cents. A percentage discount floors fractional
226
+ cents (integer division), per \`money.floor_cents\`. No banker's rounding is
227
+ needed because the cap and the discounts are all integer-cents operations.
228
+
229
+ ## Empty input
230
+
231
+ With an empty \`rules\` list the total equals the subtotal unchanged.
232
+ `;
233
+ const ARCHITECTURE_MD = `# Architecture
234
+
235
+ \`\`\`
236
+ catalog.py ──▶ handlers build a Cart (models.py)
237
+
238
+
239
+ cart.subtotal() ── integer cents
240
+
241
+
242
+ pricing.compute_total(subtotal, rules) ──▶ final total
243
+
244
+
245
+ rules.py (PercentRule, FixedRule)
246
+ money.py (integer-cents helpers)
247
+ \`\`\`
248
+
249
+ ## Module responsibilities
250
+
251
+ - **catalog.py** owns product prices. Nothing downstream mutates it.
252
+ - **models.py** turns line items into a subtotal. The pricing engine never sees
253
+ individual lines, only the subtotal - this keeps the discount rules independent
254
+ of how the cart was built.
255
+ - **rules.py** defines discount rules. A rule is a pure function of the amount it
256
+ is handed; it does not know about ordering or caps. Those are the *engine's*
257
+ responsibility, defined in docs/SPEC.md, not the rule's.
258
+ - **money.py** keeps everything in integer cents. Floats never touch money.
259
+ - **pricing.py** is the only place the SPEC's ordering + cap rules are enforced.
260
+
261
+ ## Invariant
262
+
263
+ Because rules are pure and stateless, the engine must not let one rule's output
264
+ feed the next rule's input. Read docs/SPEC.md "Base amount" - each rule sees the
265
+ original subtotal. A bug here looks like discounts that are slightly too small
266
+ (because they compound) and totals that drop below half the subtotal (because the
267
+ cap is missing).
268
+ `;
269
+ const CHANGELOG_MD = `# Changelog
270
+
271
+ ## Unreleased
272
+
273
+ - Nothing yet.
274
+
275
+ ## v3.0
276
+
277
+ - **Spec:** clarified that the 50% combined cap applies to the *sum* of
278
+ discounts, not per rule. No code change was landed for this - see the open bug
279
+ where large discounts still drive totals below 50%.
280
+
281
+ ## v2.0
282
+
283
+ - Added the **50% combined discount cap** to docs/SPEC.md. Previously discounts
284
+ were uncapped. The engine was supposed to be updated to enforce it.
285
+ - Added \`FixedRule\`.
286
+
287
+ ## v1.1
288
+
289
+ - Established that discounts apply to the **original subtotal**, so multiple
290
+ rules do not compound. Documented under docs/SPEC.md "Base amount".
291
+
292
+ ## v1.0
293
+
294
+ - Initial engine: \`compute_total\`, \`PercentRule\`, integer-cents money.
295
+ `;
296
+ const HANDLERS_PY = `"""Request handlers. Build a cart from SKUs, then price it. These are here so
297
+ the module graph looks like a real service; the pricing math lives in pricing.py.
298
+ """
299
+ from catalog import price_of
300
+ from models import Cart, LineItem
301
+ from pricing import compute_total
302
+
303
+
304
+ def price_order(skus_with_qty, rules):
305
+ cart = Cart()
306
+ for sku, qty in skus_with_qty:
307
+ unit = price_of(sku)
308
+ if unit is None:
309
+ raise KeyError("unknown sku: %s" % sku)
310
+ cart.add(LineItem(sku, unit, qty))
311
+ return compute_total(cart.subtotal(), rules)
312
+ `;
313
+ /** The hidden oracle - never shown to the model, written only at test time. Its
314
+ * expectations encode docs/SPEC.md exactly. */
315
+ export const EXTRA_HIDDEN_TEST = `import unittest
316
+
317
+ from pricing import compute_total
318
+ from rules import PercentRule, FixedRule
319
+
320
+
321
+ class TestPricing(unittest.TestCase):
322
+ def test_empty_rules(self):
323
+ self.assertEqual(compute_total(10000, []), 10000)
324
+
325
+ def test_single_percent(self):
326
+ self.assertEqual(compute_total(10000, [PercentRule("a", 20)]), 8000)
327
+
328
+ def test_two_rules_do_not_compound(self):
329
+ # 30% + 40% of the ORIGINAL 10000 = 3000 + 4000 = 7000, capped at 5000.
330
+ rules = [PercentRule("a", 30), PercentRule("b", 40)]
331
+ self.assertEqual(compute_total(10000, rules), 5000)
332
+
333
+ def test_combined_cap(self):
334
+ # A single 60% rule is capped at 50%.
335
+ self.assertEqual(compute_total(10000, [PercentRule("big", 60)]), 5000)
336
+
337
+ def test_under_cap(self):
338
+ # 10% + 15% = 2500 discount, below the cap.
339
+ rules = [PercentRule("a", 10), PercentRule("b", 15)]
340
+ self.assertEqual(compute_total(10000, rules), 7500)
341
+
342
+ def test_fixed_and_percent_capped(self):
343
+ # 4000 fixed + 30% (3000) = 7000, capped at 5000.
344
+ rules = [FixedRule("f", 4000), PercentRule("p", 30)]
345
+ self.assertEqual(compute_total(10000, rules), 5000)
346
+
347
+
348
+ if __name__ == "__main__":
349
+ unittest.main()
350
+ `;
351
+ /**
352
+ * The files the model can see and explore. Python modules are the working copy it
353
+ * edits; markdown is read-only reference. The hidden test is intentionally NOT
354
+ * here.
355
+ */
356
+ export const EXTRA_CORPUS = {
357
+ "README.md": README_MD,
358
+ "docs/SPEC.md": SPEC_MD,
359
+ "docs/ARCHITECTURE.md": ARCHITECTURE_MD,
360
+ "docs/CHANGELOG.md": CHANGELOG_MD,
361
+ "pricing.py": PRICING_PY,
362
+ "rules.py": RULES_PY,
363
+ "money.py": MONEY_PY,
364
+ "models.py": MODELS_PY,
365
+ "catalog.py": CATALOG_PY,
366
+ "handlers.py": HANDLERS_PY,
367
+ };
368
+ /** The Python modules that make up the runnable working copy (no docs). */
369
+ export const EXTRA_PY_FILES = [
370
+ "pricing.py",
371
+ "rules.py",
372
+ "money.py",
373
+ "models.py",
374
+ "catalog.py",
375
+ "handlers.py",
376
+ ];
377
+ /** The one file the model is meant to fix. */
378
+ export const EXTRA_TARGET_FILE = "pricing.py";
379
+ //# sourceMappingURL=corpus.js.map