opencode-agent-skill 7.7.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 +163 -0
- package/LICENSE +9 -0
- package/README.md +581 -0
- package/bin/ocskill.mjs +975 -0
- package/docs/DETERMINISTIC-TOOLS.md +88 -0
- package/docs/ENGINEERING-DESIGN.md +176 -0
- package/docs/EVALS.md +136 -0
- package/docs/NPM-PUBLISH.md +102 -0
- package/docs/OPENCODE-COMPAT.md +109 -0
- package/docs/RESEARCH-SOURCES.md +37 -0
- package/docs/TRACE-SCHEMA.md +109 -0
- package/docs/V7-INTELLIGENCE-RUNTIME.md +166 -0
- package/evals/live/fixtures/engineering-bench/package.json +1 -0
- package/evals/live/fixtures/engineering-bench/src/api-errors.mjs +3 -0
- package/evals/live/fixtures/engineering-bench/src/authz.mjs +3 -0
- package/evals/live/fixtures/engineering-bench/src/cache-tags.mjs +3 -0
- package/evals/live/fixtures/engineering-bench/src/config.mjs +3 -0
- package/evals/live/fixtures/engineering-bench/src/contract-consumer.mjs +6 -0
- package/evals/live/fixtures/engineering-bench/src/contract-producer.mjs +3 -0
- package/evals/live/fixtures/engineering-bench/src/dedupe.mjs +3 -0
- package/evals/live/fixtures/engineering-bench/src/dependency.mjs +3 -0
- package/evals/live/fixtures/engineering-bench/src/discount.mjs +3 -0
- package/evals/live/fixtures/engineering-bench/src/inventory.mjs +3 -0
- package/evals/live/fixtures/engineering-bench/src/migration.mjs +3 -0
- package/evals/live/fixtures/engineering-bench/src/money.mjs +3 -0
- package/evals/live/fixtures/engineering-bench/src/pagination.mjs +5 -0
- package/evals/live/fixtures/engineering-bench/src/path-safe.mjs +5 -0
- package/evals/live/fixtures/engineering-bench/src/payment.mjs +5 -0
- package/evals/live/fixtures/engineering-bench/src/query-sort.mjs +3 -0
- package/evals/live/fixtures/engineering-bench/src/react-state.mjs +8 -0
- package/evals/live/fixtures/engineering-bench/src/retry.mjs +3 -0
- package/evals/live/fixtures/engineering-bench/src/rn-platform.mjs +3 -0
- package/evals/live/fixtures/engineering-bench/src/upload.mjs +3 -0
- package/evals/live/fixtures/engineering-bench/src/webhook.mjs +3 -0
- package/evals/live/graders/engineering-bench.mjs +239 -0
- package/evals/live/tasks.json +126 -0
- package/evals/long/fixtures/long-horizon/package.json +1 -0
- package/evals/long/fixtures/long-horizon/src/auth.mjs +5 -0
- package/evals/long/fixtures/long-horizon/src/checkout.mjs +9 -0
- package/evals/long/fixtures/long-horizon/src/inventory.mjs +5 -0
- package/evals/long/fixtures/long-horizon/src/money.mjs +3 -0
- package/evals/long/fixtures/long-horizon/src/payment.mjs +7 -0
- package/evals/long/fixtures/long-horizon/src/product-api.mjs +10 -0
- package/evals/long/fixtures/long-horizon/src/product-cache.mjs +3 -0
- package/evals/long/fixtures/long-horizon/src/product-service.mjs +6 -0
- package/evals/long/fixtures/long-horizon/src/product-state.mjs +8 -0
- package/evals/long/fixtures/long-horizon/src/project-api.mjs +9 -0
- package/evals/long/fixtures/long-horizon/src/project-service.mjs +7 -0
- package/evals/long/fixtures/long-horizon/src/user-consumer.mjs +3 -0
- package/evals/long/fixtures/long-horizon/src/user-migration.mjs +7 -0
- package/evals/long/fixtures/long-horizon/src/user-serializer.mjs +3 -0
- package/evals/long/fixtures/long-horizon/src/user-validation.mjs +3 -0
- package/evals/long/graders/long-horizon.mjs +209 -0
- package/evals/long/tasks.json +36 -0
- package/evals/router-triggers.json +1238 -0
- package/evals/routing.json +321 -0
- package/global-config/AGENTS.md +212 -0
- package/global-config/agents/architect.md +38 -0
- package/global-config/agents/codebase-mapper.md +41 -0
- package/global-config/agents/critic.md +37 -0
- package/global-config/agents/debugger.md +36 -0
- package/global-config/agents/executor.md +48 -0
- package/global-config/agents/integration-verifier.md +43 -0
- package/global-config/agents/plan-checker.md +43 -0
- package/global-config/agents/researcher.md +30 -0
- package/global-config/agents/reviewer.md +30 -0
- package/global-config/agents/verifier.md +33 -0
- package/global-config/commands/audit.md +8 -0
- package/global-config/commands/critique.md +8 -0
- package/global-config/commands/debug.md +8 -0
- package/global-config/commands/feature.md +8 -0
- package/global-config/commands/fix.md +8 -0
- package/global-config/commands/plan.md +8 -0
- package/global-config/commands/research.md +8 -0
- package/global-config/commands/resume.md +22 -0
- package/global-config/commands/review.md +8 -0
- package/global-config/commands/run.md +29 -0
- package/global-config/commands/verify.md +8 -0
- package/global-config/plugins/ues-router/capabilities.js +20 -0
- package/global-config/plugins/ues-router/index.js +277 -0
- package/global-config/plugins/ues-router/router.js +74 -0
- package/global-config/plugins/ues-router/safety.js +16 -0
- package/global-config/skills/accessibility/SKILL.md +10 -0
- package/global-config/skills/accessibility/references/workflow.md +17 -0
- package/global-config/skills/api-contract/SKILL.md +12 -0
- package/global-config/skills/api-contract/references/workflow.md +17 -0
- package/global-config/skills/auth-security/SKILL.md +12 -0
- package/global-config/skills/auth-security/references/workflow.md +15 -0
- package/global-config/skills/bug-diagnosis/SKILL.md +28 -0
- package/global-config/skills/change-impact-analysis/SKILL.md +23 -0
- package/global-config/skills/code-review/SKILL.md +19 -0
- package/global-config/skills/context-engineering/SKILL.md +18 -0
- package/global-config/skills/context-engineering/references/large-repo.md +16 -0
- package/global-config/skills/database-engineering/SKILL.md +12 -0
- package/global-config/skills/database-engineering/references/workflow.md +15 -0
- package/global-config/skills/dependency-management/SKILL.md +12 -0
- package/global-config/skills/dependency-management/references/workflow.md +14 -0
- package/global-config/skills/devops-engineering/SKILL.md +10 -0
- package/global-config/skills/devops-engineering/references/workflow.md +11 -0
- package/global-config/skills/django-engineering/SKILL.md +10 -0
- package/global-config/skills/django-engineering/references/workflow.md +11 -0
- package/global-config/skills/documentation-engineering/SKILL.md +10 -0
- package/global-config/skills/documentation-engineering/references/workflow.md +15 -0
- package/global-config/skills/dotnet-engineering/SKILL.md +10 -0
- package/global-config/skills/dotnet-engineering/references/workflow.md +11 -0
- package/global-config/skills/ecommerce-engineering/SKILL.md +10 -0
- package/global-config/skills/ecommerce-engineering/references/workflow.md +17 -0
- package/global-config/skills/engineering-orchestrator/SKILL.md +29 -0
- package/global-config/skills/engineering-orchestrator/references/delegation.md +22 -0
- package/global-config/skills/engineering-orchestrator/references/evaluator-loop.md +18 -0
- package/global-config/skills/engineering-orchestrator/references/long-horizon.md +57 -0
- package/global-config/skills/engineering-orchestrator/references/model-escalation.md +19 -0
- package/global-config/skills/engineering-orchestrator/references/retry-policy.md +12 -0
- package/global-config/skills/engineering-orchestrator/references/routing.md +39 -0
- package/global-config/skills/engineering-orchestrator/references/verification-matrix.md +18 -0
- package/global-config/skills/fastapi-engineering/SKILL.md +10 -0
- package/global-config/skills/fastapi-engineering/references/workflow.md +13 -0
- package/global-config/skills/file-upload-engineering/SKILL.md +10 -0
- package/global-config/skills/file-upload-engineering/references/workflow.md +17 -0
- package/global-config/skills/flutter-engineering/SKILL.md +10 -0
- package/global-config/skills/flutter-engineering/references/workflow.md +13 -0
- package/global-config/skills/git-safety/SKILL.md +10 -0
- package/global-config/skills/git-safety/references/workflow.md +15 -0
- package/global-config/skills/implementation-engineer/SKILL.md +10 -0
- package/global-config/skills/implementation-engineer/references/workflow.md +14 -0
- package/global-config/skills/java-spring-engineering/SKILL.md +10 -0
- package/global-config/skills/java-spring-engineering/references/workflow.md +13 -0
- package/global-config/skills/long-task-state/SKILL.md +28 -0
- package/global-config/skills/long-task-state/references/context-ledger.md +27 -0
- package/global-config/skills/long-task-state/templates/STATE.md +48 -0
- package/global-config/skills/nestjs-engineering/SKILL.md +10 -0
- package/global-config/skills/nestjs-engineering/references/workflow.md +11 -0
- package/global-config/skills/nextjs-engineering/SKILL.md +12 -0
- package/global-config/skills/nextjs-engineering/references/workflow.md +15 -0
- package/global-config/skills/nodejs-engineering/SKILL.md +12 -0
- package/global-config/skills/nodejs-engineering/references/workflow.md +11 -0
- package/global-config/skills/payment-engineering/SKILL.md +12 -0
- package/global-config/skills/payment-engineering/references/workflow.md +19 -0
- package/global-config/skills/performance-engineering/SKILL.md +10 -0
- package/global-config/skills/performance-engineering/references/workflow.md +17 -0
- package/global-config/skills/python-engineering/SKILL.md +10 -0
- package/global-config/skills/python-engineering/references/workflow.md +11 -0
- package/global-config/skills/react-engineering/SKILL.md +14 -0
- package/global-config/skills/react-engineering/references/workflow.md +16 -0
- package/global-config/skills/react-native-engineering/SKILL.md +14 -0
- package/global-config/skills/react-native-engineering/references/workflow.md +16 -0
- package/global-config/skills/repo-explorer/SKILL.md +17 -0
- package/global-config/skills/research-verification/SKILL.md +18 -0
- package/global-config/skills/research-verification/references/source-hierarchy.md +12 -0
- package/global-config/skills/rest-api-design/SKILL.md +10 -0
- package/global-config/skills/rest-api-design/references/workflow.md +18 -0
- package/global-config/skills/software-architect/SKILL.md +10 -0
- package/global-config/skills/software-architect/references/workflow.md +18 -0
- package/global-config/skills/task-planner/SKILL.md +21 -0
- package/global-config/skills/task-planner/references/plan-schema.md +56 -0
- package/global-config/skills/test-driven-development/SKILL.md +22 -0
- package/global-config/skills/test-driven-development/references/writing-good-tests.md +21 -0
- package/global-config/skills/test-verification/SKILL.md +20 -0
- package/global-config/skills/ui-ux-engineering/SKILL.md +10 -0
- package/global-config/skills/ui-ux-engineering/references/workflow.md +17 -0
- package/global-config/skills/web-security-review/SKILL.md +10 -0
- package/global-config/skills/web-security-review/references/workflow.md +22 -0
- package/lib/context-manifest.mjs +101 -0
- package/lib/control-center.mjs +148 -0
- package/lib/eval-auth.mjs +21 -0
- package/lib/eval-report.mjs +72 -0
- package/lib/eval-telemetry.mjs +155 -0
- package/lib/evidence-receipt.mjs +50 -0
- package/lib/hermes-bridge.mjs +28 -0
- package/lib/ids.mjs +21 -0
- package/lib/installer.mjs +636 -0
- package/lib/learning-engine.mjs +161 -0
- package/lib/model-config.mjs +88 -0
- package/lib/model-policy.mjs +71 -0
- package/lib/opencode-compat.mjs +86 -0
- package/lib/orchestrator-policy.mjs +35 -0
- package/lib/process-runner.mjs +117 -0
- package/lib/repo-graph.mjs +135 -0
- package/lib/repo-inspect.mjs +264 -0
- package/lib/review-scope.mjs +98 -0
- package/lib/router-config.mjs +40 -0
- package/lib/task-engine.mjs +777 -0
- package/lib/task-graph.mjs +262 -0
- package/lib/update-resolver.mjs +43 -0
- package/lib/verification-plan.mjs +52 -0
- package/lib/version.mjs +47 -0
- package/lib/workspace-snapshot.mjs +45 -0
- package/lib/worktree-sandbox.mjs +59 -0
- package/package.json +69 -0
- package/scripts/check-working-tree.mjs +2 -0
- package/scripts/collect-evidence.mjs +2 -0
- package/scripts/control-center.mjs +37 -0
- package/scripts/detect-stack.mjs +2 -0
- package/scripts/detect-test-commands.mjs +2 -0
- package/scripts/eval-live.mjs +437 -0
- package/scripts/eval-report.mjs +49 -0
- package/scripts/eval-router.mjs +45 -0
- package/scripts/eval-skills.mjs +71 -0
- package/scripts/impact-map.mjs +4 -0
- package/scripts/install.mjs +61 -0
- package/scripts/repo-map.mjs +2 -0
- package/scripts/smoke-packed-install.mjs +326 -0
- package/scripts/syntax-check.mjs +35 -0
- package/scripts/uninstall.mjs +21 -0
- package/scripts/validate-live-suite.mjs +65 -0
- package/scripts/validate.mjs +133 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 2,
|
|
3
|
+
"description": "Executable multi-domain coding-agent benchmark tasks. Each task runs in an isolated workspace and is graded outside the workspace.",
|
|
4
|
+
"tasks": [
|
|
5
|
+
{
|
|
6
|
+
"id": "js-discount-regression",
|
|
7
|
+
"fixture": "fixtures/engineering-bench",
|
|
8
|
+
"prompt": "Fix calculateDiscount(price, percent) in src/discount.mjs. Percent is 0..100, so 20 means a 20% discount. Reject non-finite/non-number price or percent with TypeError and percent outside 0..100 with RangeError. Preserve the export and do not weaken the requested semantics.",
|
|
9
|
+
"grader": "graders/engineering-bench.mjs"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"id": "auth-resource-ownership",
|
|
13
|
+
"fixture": "fixtures/engineering-bench",
|
|
14
|
+
"prompt": "Fix canEditResource(user, resource) in src/authz.mjs. Missing inputs deny. Suspended users always deny. Admin users may edit any non-missing resource. Non-admin users may edit only when user.id equals resource.ownerId AND user.tenantId equals resource.tenantId. Return a boolean and do not mutate inputs.",
|
|
15
|
+
"grader": "graders/engineering-bench.mjs"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"id": "api-pagination-contract",
|
|
19
|
+
"fixture": "fixtures/engineering-bench",
|
|
20
|
+
"prompt": "Fix paginate(items, options) in src/pagination.mjs. pages are 1-indexed; defaults are page=1 and pageSize=10. items must be an array. page/pageSize must be positive integers. Return {items,total,page,pageSize,totalPages}; out-of-range pages return an empty items array. Use TypeError for wrong types and RangeError for invalid numeric ranges.",
|
|
21
|
+
"grader": "graders/engineering-bench.mjs"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"id": "inventory-reservation",
|
|
25
|
+
"fixture": "fixtures/engineering-bench",
|
|
26
|
+
"prompt": "Fix reserveStock(stock, quantity) in src/inventory.mjs. Both values must be finite integers; stock must be >=0 and quantity must be >0. Throw TypeError for non-number/non-finite/non-integer values and RangeError for invalid ranges or insufficient stock. Return remaining stock without mutating external state.",
|
|
27
|
+
"grader": "graders/engineering-bench.mjs"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"id": "payment-idempotency",
|
|
31
|
+
"fixture": "fixtures/engineering-bench",
|
|
32
|
+
"prompt": "Fix applyPaymentEvent(order, event) in src/payment.mjs. Do not mutate order. Duplicate event.id values already in order.processedEvents must be idempotent. A new event must have a non-empty id. For status='succeeded', amountCents and currency must exactly match order.totalCents/order.currency or throw RangeError, then mark status paid. Failed events must not mark paid. Record each new event id exactly once.",
|
|
33
|
+
"grader": "graders/engineering-bench.mjs"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"id": "webhook-ordering",
|
|
37
|
+
"fixture": "fixtures/engineering-bench",
|
|
38
|
+
"prompt": "Fix advancePaymentState(state, event) in src/webhook.mjs. Ignore duplicate/stale events whose integer sequence <= state.lastSequence. Newer events must follow legal transitions pending->authorized|failed, authorized->paid|failed, paid->refunded; same-status newer events are allowed. Illegal transitions throw RangeError. Return a new state and never mutate inputs.",
|
|
39
|
+
"grader": "graders/engineering-bench.mjs"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"id": "secure-file-upload",
|
|
43
|
+
"fixture": "fixtures/engineering-bench",
|
|
44
|
+
"prompt": "Fix validateUpload(file, options) in src/upload.mjs. file must have name/type/size. Reject names containing path separators, '..', or NUL. size must be a finite non-negative integer no larger than options.maxBytes. type must be in options.allowedTypes. Throw TypeError for malformed inputs and RangeError for size violations; return true when valid.",
|
|
45
|
+
"grader": "graders/engineering-bench.mjs"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"id": "path-traversal-defense",
|
|
49
|
+
"fixture": "fixtures/engineering-bench",
|
|
50
|
+
"prompt": "Fix safeJoin(root, userPath) in src/path-safe.mjs. Return the absolute resolved path only when userPath is a non-empty relative path that stays inside root. Reject absolute paths, traversal outside root, and NUL with RangeError; wrong argument types use TypeError. The check must be cross-platform.",
|
|
51
|
+
"grader": "graders/engineering-bench.mjs"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"id": "stable-api-errors",
|
|
55
|
+
"fixture": "fixtures/engineering-bench",
|
|
56
|
+
"prompt": "Fix toHttpError(error) in src/api-errors.mjs. Map codes VALIDATION->400, FORBIDDEN->403, NOT_FOUND->404, CONFLICT->409 and unknown/missing->500. Return {status,body:{error:{code,message}}}. Unknown errors must expose code INTERNAL and message 'Internal server error'; never expose stack or arbitrary extra fields.",
|
|
57
|
+
"grader": "graders/engineering-bench.mjs"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"id": "http-retry-policy",
|
|
61
|
+
"fixture": "fixtures/engineering-bench",
|
|
62
|
+
"prompt": "Fix shouldRetry({status,attempt,maxAttempts}) in src/retry.mjs. attempt and maxAttempts are positive integers and status is an integer HTTP status. Retry only while attempt < maxAttempts and status is 408, 429, or 500..599. Return false for other statuses. Invalid input types/ranges should throw TypeError or RangeError appropriately.",
|
|
63
|
+
"grader": "graders/engineering-bench.mjs"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"id": "dedupe-stable-order",
|
|
67
|
+
"fixture": "fixtures/engineering-bench",
|
|
68
|
+
"prompt": "Fix dedupeById(items) in src/dedupe.mjs. items must be an array of objects with non-null id. Preserve the first occurrence of each id and original order, do not mutate inputs, and treat numeric 1 and string '1' as distinct ids. Malformed items throw TypeError.",
|
|
69
|
+
"grader": "graders/engineering-bench.mjs"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"id": "legacy-user-migration",
|
|
73
|
+
"fixture": "fixtures/engineering-bench",
|
|
74
|
+
"prompt": "Fix migrateUsers(rows) in src/migration.mjs. Return new objects without mutating rows. If firstName/lastName already exist, preserve them and remove legacy fullName. Otherwise split trimmed fullName on whitespace: first token -> firstName, remaining tokens -> lastName; an empty/missing fullName becomes empty strings. Preserve unrelated fields.",
|
|
75
|
+
"grader": "graders/engineering-bench.mjs"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"id": "money-integer-invariants",
|
|
79
|
+
"fixture": "fixtures/engineering-bench",
|
|
80
|
+
"prompt": "Fix orderTotal(lines) in src/money.mjs. Each line uses integer unitPriceCents>=0, integer quantity>0, optional integer discountCents>=0. Line total is unitPriceCents*quantity-discountCents and may not go below zero. Return an integer cent total. Malformed numeric types use TypeError; invalid ranges use RangeError.",
|
|
81
|
+
"grader": "graders/engineering-bench.mjs"
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"id": "sql-sort-allowlist",
|
|
85
|
+
"fixture": "fixtures/engineering-bench",
|
|
86
|
+
"prompt": "Fix buildSort(sort) in src/query-sort.mjs. Accept an object {field,direction}. field allowlist: createdAt->created_at, name->name, price->price_cents. direction accepts asc/desc case-insensitively. Return exactly 'ORDER BY <mapped-column> <ASC|DESC>'. Reject all other values with RangeError and malformed input with TypeError; never interpolate arbitrary field text.",
|
|
87
|
+
"grader": "graders/engineering-bench.mjs"
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"id": "react-stale-request",
|
|
91
|
+
"fixture": "fixtures/engineering-bench",
|
|
92
|
+
"prompt": "Fix reducer in src/react-state.mjs for request races. start sets requestId, loading=true, error=null. success/error actions apply only when action.requestId equals current state.requestId; stale completions return the unchanged state object. Matching success sets data and loading=false/error=null; matching error sets error and loading=false. Unknown actions return state.",
|
|
93
|
+
"grader": "graders/engineering-bench.mjs"
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"id": "react-native-keyboard-offset",
|
|
97
|
+
"fixture": "fixtures/engineering-bench",
|
|
98
|
+
"prompt": "Fix keyboardOffset(platform, safeAreaTop, headerHeight) in src/rn-platform.mjs. platform must be 'ios' or 'android'; offsets must be finite non-negative numbers. iOS returns safeAreaTop+headerHeight; Android returns headerHeight. Invalid types use TypeError and invalid ranges/platform use RangeError.",
|
|
99
|
+
"grader": "graders/engineering-bench.mjs"
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"id": "dependency-caret-range",
|
|
103
|
+
"fixture": "fixtures/engineering-bench",
|
|
104
|
+
"prompt": "Fix satisfiesCaret(version, range) in src/dependency.mjs for stable numeric semver x.y.z and caret ranges ^x.y.z. ^1.2.3 allows >=1.2.3 and <2.0.0; ^0.2.3 allows >=0.2.3 and <0.3.0; ^0.0.3 allows only 0.0.3. Return false for malformed versions/ranges instead of throwing.",
|
|
105
|
+
"grader": "graders/engineering-bench.mjs"
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"id": "strict-env-boolean",
|
|
109
|
+
"fixture": "fixtures/engineering-bench",
|
|
110
|
+
"prompt": "Fix readBooleanEnv(value, fallback=false) in src/config.mjs. undefined/null/empty-string use Boolean(fallback). Boolean inputs return themselves. Case-insensitive trimmed strings true/1/yes/on => true and false/0/no/off => false. Any other value throws TypeError.",
|
|
111
|
+
"grader": "graders/engineering-bench.mjs"
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"id": "cache-invalidation-tags",
|
|
115
|
+
"fixture": "fixtures/engineering-bench",
|
|
116
|
+
"prompt": "Fix tagsForProductMutation(product) in src/cache-tags.mjs. product must contain a non-empty id. Return unique tags in this order: 'products', 'product:<id>', then optional 'category:<categoryId>' and 'seller:<sellerId>' when those values are non-null/non-empty. Do not emit undefined/empty tags and do not mutate product.",
|
|
117
|
+
"grader": "graders/engineering-bench.mjs"
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"id": "multi-file-contract-compatibility",
|
|
121
|
+
"fixture": "fixtures/engineering-bench",
|
|
122
|
+
"prompt": "Repair the user serialization contract across src/contract-producer.mjs and src/contract-consumer.mjs. serializeUser must preserve id and legacy name while also exposing displayName, using user.displayName when non-empty otherwise falling back to name. userLabel must prefer the serialized displayName but remain compatible with name. Do not remove the legacy name field.",
|
|
123
|
+
"grader": "graders/engineering-bench.mjs"
|
|
124
|
+
}
|
|
125
|
+
]
|
|
126
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"name":"ues-long-horizon-bench","private":true,"type":"module"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { updateProduct } from "./product-service.mjs"
|
|
2
|
+
|
|
3
|
+
export function handleProductUpdate(input) {
|
|
4
|
+
try {
|
|
5
|
+
const result = updateProduct(input.product, input.patch)
|
|
6
|
+
return { status: 200, body: { product: result.product }, revalidate: result.tags }
|
|
7
|
+
} catch (error) {
|
|
8
|
+
return { status: 500, body: { error: { message: error.message, stack: error.stack } } }
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export const initialProductState = { requestId: null, loading: false, data: null, error: null }
|
|
2
|
+
|
|
3
|
+
export function productReducer(state = initialProductState, action) {
|
|
4
|
+
if (action.type === "start") return { ...state, requestId: action.requestId, loading: true, error: null }
|
|
5
|
+
if (action.type === "success") return { ...state, data: action.data, loading: false, error: null }
|
|
6
|
+
if (action.type === "error") return { ...state, error: action.error, loading: false }
|
|
7
|
+
return state
|
|
8
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { updateProject } from "./project-service.mjs"
|
|
2
|
+
|
|
3
|
+
export function handleProjectUpdate(input) {
|
|
4
|
+
try {
|
|
5
|
+
return { status: 200, body: { project: updateProject(input.user, input.project, input.patch) } }
|
|
6
|
+
} catch (error) {
|
|
7
|
+
return { status: 500, body: { error } }
|
|
8
|
+
}
|
|
9
|
+
}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import assert from "node:assert/strict"
|
|
2
|
+
import path from "node:path"
|
|
3
|
+
import { spawnSync } from "node:child_process"
|
|
4
|
+
import { fileURLToPath, pathToFileURL } from "node:url"
|
|
5
|
+
|
|
6
|
+
const workspace = process.env.UES_EVAL_WORKSPACE
|
|
7
|
+
const task = process.env.UES_EVAL_TASK
|
|
8
|
+
if (!workspace || !task) {
|
|
9
|
+
console.error("UES_EVAL_WORKSPACE and UES_EVAL_TASK are required")
|
|
10
|
+
process.exit(2)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const load = async (file) =>
|
|
14
|
+
import(pathToFileURL(path.join(workspace, "src", file)).href + "?eval=" + Date.now() + "-" + Math.random())
|
|
15
|
+
|
|
16
|
+
const throws = (fn, Type) => assert.throws(fn, Type)
|
|
17
|
+
|
|
18
|
+
switch (task) {
|
|
19
|
+
case "long-checkout-integration": {
|
|
20
|
+
const { calculateTotal } = await load("money.mjs")
|
|
21
|
+
const { reserveAll } = await load("inventory.mjs")
|
|
22
|
+
const { applyCharge } = await load("payment.mjs")
|
|
23
|
+
const { checkout } = await load("checkout.mjs")
|
|
24
|
+
|
|
25
|
+
const lines = [
|
|
26
|
+
{ sku: "a", unitPriceCents: 250, quantity: 2 },
|
|
27
|
+
{ sku: "a", unitPriceCents: 100, quantity: 1 },
|
|
28
|
+
{ sku: "b", unitPriceCents: 50, quantity: 3 },
|
|
29
|
+
]
|
|
30
|
+
assert.equal(calculateTotal(lines), 750)
|
|
31
|
+
throws(() => calculateTotal("x"), TypeError)
|
|
32
|
+
throws(() => calculateTotal([{ sku: "a", unitPriceCents: 1.5, quantity: 1 }]), TypeError)
|
|
33
|
+
throws(() => calculateTotal([{ sku: "a", unitPriceCents: -1, quantity: 1 }]), RangeError)
|
|
34
|
+
throws(() => calculateTotal([{ sku: "a", unitPriceCents: 100, quantity: 0 }]), RangeError)
|
|
35
|
+
|
|
36
|
+
const stock = { a: 5, b: 4 }
|
|
37
|
+
const reserved = reserveAll(stock, lines)
|
|
38
|
+
assert.deepEqual(reserved, { a: 2, b: 1 })
|
|
39
|
+
assert.deepEqual(stock, { a: 5, b: 4 })
|
|
40
|
+
throws(() => reserveAll(stock, [...lines, { sku: "b", unitPriceCents: 1, quantity: 3 }]), RangeError)
|
|
41
|
+
assert.deepEqual(stock, { a: 5, b: 4 })
|
|
42
|
+
throws(() => reserveAll(stock, [{ sku: "missing", unitPriceCents: 1, quantity: 1 }]), RangeError)
|
|
43
|
+
|
|
44
|
+
const order = {
|
|
45
|
+
id: "o1",
|
|
46
|
+
status: "pending",
|
|
47
|
+
totalCents: 750,
|
|
48
|
+
currency: "USD",
|
|
49
|
+
processedEvents: [],
|
|
50
|
+
lines,
|
|
51
|
+
}
|
|
52
|
+
const paid = applyCharge(order, { id: "evt1", status: "succeeded", amountCents: 750, currency: "USD" })
|
|
53
|
+
assert.equal(order.status, "pending")
|
|
54
|
+
assert.deepEqual(order.processedEvents, [])
|
|
55
|
+
assert.equal(paid.status, "paid")
|
|
56
|
+
assert.deepEqual(paid.processedEvents, ["evt1"])
|
|
57
|
+
assert.deepEqual(applyCharge(paid, { id: "evt1", status: "succeeded", amountCents: 750, currency: "USD" }), paid)
|
|
58
|
+
throws(() => applyCharge(order, { id: "evt2", status: "succeeded", amountCents: 749, currency: "USD" }), RangeError)
|
|
59
|
+
|
|
60
|
+
const result = checkout(order, stock, { id: "evt3", status: "succeeded", amountCents: 750, currency: "USD" })
|
|
61
|
+
assert.equal(result.order.status, "paid")
|
|
62
|
+
assert.deepEqual(result.stock, { a: 2, b: 1 })
|
|
63
|
+
assert.deepEqual(stock, { a: 5, b: 4 })
|
|
64
|
+
assert.equal(order.status, "pending")
|
|
65
|
+
throws(() => checkout({ ...order, totalCents: 999 }, stock, { id: "evt4", status: "succeeded", amountCents: 750, currency: "USD" }), RangeError)
|
|
66
|
+
break
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
case "long-tenant-security-integration": {
|
|
70
|
+
const { canEditProject } = await load("auth.mjs")
|
|
71
|
+
const { updateProject } = await load("project-service.mjs")
|
|
72
|
+
const { handleProjectUpdate } = await load("project-api.mjs")
|
|
73
|
+
|
|
74
|
+
const project = { id: "p1", tenantId: "t1", ownerId: "u1", title: "Old", description: "D" }
|
|
75
|
+
const member = { id: "u1", tenantId: "t1", role: "member" }
|
|
76
|
+
assert.equal(canEditProject(member, project), true)
|
|
77
|
+
assert.equal(canEditProject({ ...member, tenantId: "t2" }, project), false)
|
|
78
|
+
assert.equal(canEditProject({ ...member, id: "u2" }, project), false)
|
|
79
|
+
assert.equal(canEditProject({ id: "a", tenantId: "t1", role: "admin" }, project), true)
|
|
80
|
+
assert.equal(canEditProject({ id: "a", tenantId: "t2", role: "admin" }, project), false)
|
|
81
|
+
assert.equal(canEditProject({ ...member, suspended: true }, project), false)
|
|
82
|
+
|
|
83
|
+
const updated = updateProject(member, project, { title: "New" })
|
|
84
|
+
assert.deepEqual(project, { id: "p1", tenantId: "t1", ownerId: "u1", title: "Old", description: "D" })
|
|
85
|
+
assert.deepEqual(updated, { id: "p1", tenantId: "t1", ownerId: "u1", title: "New", description: "D" })
|
|
86
|
+
|
|
87
|
+
assert.throws(
|
|
88
|
+
() => updateProject({ ...member, tenantId: "t2" }, project, { title: "X" }),
|
|
89
|
+
(error) => error && error.code === "FORBIDDEN",
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
const forbidden = handleProjectUpdate({
|
|
93
|
+
user: { ...member, tenantId: "t2" },
|
|
94
|
+
project,
|
|
95
|
+
patch: { title: "X" },
|
|
96
|
+
})
|
|
97
|
+
assert.deepEqual(forbidden, { status: 403, body: { error: { code: "FORBIDDEN", message: "Forbidden" } } })
|
|
98
|
+
|
|
99
|
+
const invalid = handleProjectUpdate({ user: member, project, patch: { tenantId: "evil" } })
|
|
100
|
+
assert.deepEqual(invalid, { status: 400, body: { error: { code: "VALIDATION", message: "Invalid request" } } })
|
|
101
|
+
|
|
102
|
+
const success = handleProjectUpdate({ user: member, project, patch: { description: "New D" } })
|
|
103
|
+
assert.equal(success.status, 200)
|
|
104
|
+
assert.equal(success.body.project.description, "New D")
|
|
105
|
+
assert.equal(success.body.project.tenantId, "t1")
|
|
106
|
+
break
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
case "long-user-contract-migration": {
|
|
110
|
+
const { migrateUser } = await load("user-migration.mjs")
|
|
111
|
+
const { serializeUser } = await load("user-serializer.mjs")
|
|
112
|
+
const { validateSerializedUser } = await load("user-validation.mjs")
|
|
113
|
+
const { userLabel } = await load("user-consumer.mjs")
|
|
114
|
+
|
|
115
|
+
const legacy = { id: 1, fullName: " Ada Lovelace ", name: "Legacy Ada", extra: true }
|
|
116
|
+
const migrated = migrateUser(legacy)
|
|
117
|
+
assert.deepEqual(legacy, { id: 1, fullName: " Ada Lovelace ", name: "Legacy Ada", extra: true })
|
|
118
|
+
assert.deepEqual(migrated, { id: 1, name: "Legacy Ada", extra: true, firstName: "Ada", lastName: "Lovelace" })
|
|
119
|
+
|
|
120
|
+
const existing = migrateUser({ id: 2, fullName: "Ignore Me", firstName: "Existing", lastName: "Name", x: 1 })
|
|
121
|
+
assert.deepEqual(existing, { id: 2, firstName: "Existing", lastName: "Name", x: 1 })
|
|
122
|
+
|
|
123
|
+
const serialized = serializeUser(migrated)
|
|
124
|
+
assert.deepEqual(serialized, { id: 1, name: "Legacy Ada", displayName: "Ada Lovelace" })
|
|
125
|
+
assert.deepEqual(
|
|
126
|
+
serializeUser({ id: 3, name: "Legacy", displayName: "Preferred", firstName: "A", lastName: "B" }),
|
|
127
|
+
{ id: 3, name: "Legacy", displayName: "Preferred" },
|
|
128
|
+
)
|
|
129
|
+
assert.deepEqual(serializeUser({ id: 4, name: "Only Legacy" }), { id: 4, name: "Only Legacy", displayName: "Only Legacy" })
|
|
130
|
+
|
|
131
|
+
assert.equal(validateSerializedUser(serialized), true)
|
|
132
|
+
assert.equal(validateSerializedUser({ id: 1, displayName: "" }), false)
|
|
133
|
+
assert.equal(validateSerializedUser({ id: null, displayName: "X" }), false)
|
|
134
|
+
assert.equal(validateSerializedUser({ id: 1, displayName: "X", name: "" }), false)
|
|
135
|
+
|
|
136
|
+
assert.equal(userLabel({ id: 1, displayName: "Preferred", name: "Legacy" }), "Preferred")
|
|
137
|
+
assert.equal(userLabel({ id: 1, name: "Legacy" }), "Legacy")
|
|
138
|
+
break
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
case "long-product-race-cache": {
|
|
142
|
+
const { initialProductState, productReducer } = await load("product-state.mjs")
|
|
143
|
+
const { tagsForProduct } = await load("product-cache.mjs")
|
|
144
|
+
const { updateProduct } = await load("product-service.mjs")
|
|
145
|
+
const { handleProductUpdate } = await load("product-api.mjs")
|
|
146
|
+
|
|
147
|
+
const started = productReducer(initialProductState, { type: "start", requestId: 2 })
|
|
148
|
+
const stale = productReducer(started, { type: "success", requestId: 1, data: { id: "old" } })
|
|
149
|
+
assert.equal(stale, started)
|
|
150
|
+
assert.deepEqual(
|
|
151
|
+
productReducer(started, { type: "success", requestId: 2, data: { id: "new" } }),
|
|
152
|
+
{ requestId: 2, loading: false, data: { id: "new" }, error: null },
|
|
153
|
+
)
|
|
154
|
+
const staleError = productReducer(started, { type: "error", requestId: 1, error: "old" })
|
|
155
|
+
assert.equal(staleError, started)
|
|
156
|
+
|
|
157
|
+
assert.deepEqual(
|
|
158
|
+
tagsForProduct({ id: "p1", categoryId: "c1", sellerId: "s1" }),
|
|
159
|
+
["products", "product:p1", "category:c1", "seller:s1"],
|
|
160
|
+
)
|
|
161
|
+
assert.deepEqual(tagsForProduct({ id: "p1", categoryId: "", sellerId: null }), ["products", "product:p1"])
|
|
162
|
+
throws(() => tagsForProduct({ id: "" }), TypeError)
|
|
163
|
+
|
|
164
|
+
const product = { id: "p1", title: "Old", categoryId: "c1", sellerId: "s1", immutable: 7 }
|
|
165
|
+
const result = updateProduct(product, { title: "New", categoryId: "c2" })
|
|
166
|
+
assert.equal(product.title, "Old")
|
|
167
|
+
assert.deepEqual(result.product, { id: "p1", title: "New", categoryId: "c2", sellerId: "s1", immutable: 7 })
|
|
168
|
+
assert.deepEqual(result.tags, ["products", "product:p1", "category:c2", "seller:s1"])
|
|
169
|
+
throws(() => updateProduct(product, { id: "evil" }), TypeError)
|
|
170
|
+
|
|
171
|
+
const response = handleProductUpdate({ product, patch: { title: "API" } })
|
|
172
|
+
assert.equal(response.status, 200)
|
|
173
|
+
assert.equal(response.body.product.title, "API")
|
|
174
|
+
assert.deepEqual(response.revalidate, ["products", "product:p1", "category:c1", "seller:s1"])
|
|
175
|
+
|
|
176
|
+
const invalid = handleProductUpdate({ product, patch: { unknown: true } })
|
|
177
|
+
assert.deepEqual(invalid, { status: 400, body: { error: { code: "VALIDATION", message: "Invalid request" } } })
|
|
178
|
+
break
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
case "long-full-system-integration": {
|
|
182
|
+
const graderFile = fileURLToPath(import.meta.url)
|
|
183
|
+
const subtasks = [
|
|
184
|
+
"long-checkout-integration",
|
|
185
|
+
"long-tenant-security-integration",
|
|
186
|
+
"long-user-contract-migration",
|
|
187
|
+
"long-product-race-cache",
|
|
188
|
+
]
|
|
189
|
+
for (const subtask of subtasks) {
|
|
190
|
+
const run = spawnSync(process.execPath, [graderFile], {
|
|
191
|
+
cwd: workspace,
|
|
192
|
+
env: { ...process.env, UES_EVAL_WORKSPACE: workspace, UES_EVAL_TASK: subtask },
|
|
193
|
+
encoding: "utf8",
|
|
194
|
+
maxBuffer: 1024 * 1024,
|
|
195
|
+
})
|
|
196
|
+
assert.equal(
|
|
197
|
+
run.status,
|
|
198
|
+
0,
|
|
199
|
+
subtask + " failed inside full-system grader:\n" + (run.stderr || run.stdout || ""),
|
|
200
|
+
)
|
|
201
|
+
}
|
|
202
|
+
break
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
default:
|
|
206
|
+
throw new Error("Unknown long-horizon task: " + task)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
console.log("long-horizon hidden grader passed:", task)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 2,
|
|
3
|
+
"description": "Long-horizon weak-model baseline vs UES benchmark. UES-mode passes require both hidden behavior graders and a completed durable multi-task orchestration state.",
|
|
4
|
+
"tasks": [
|
|
5
|
+
{
|
|
6
|
+
"id": "long-checkout-integration",
|
|
7
|
+
"fixture": "fixtures/long-horizon",
|
|
8
|
+
"prompt": "Treat this as a long-horizon multi-file task and use durable/fresh-task orchestration if the environment provides it. Repair the checkout flow across src/money.mjs, src/inventory.mjs, src/payment.mjs, and src/checkout.mjs. Money is integer cents. calculateTotal(lines) must validate integer unitPriceCents>=0 and quantity>0, and sum exactly. reserveAll(stock, lines) must be immutable and all-or-nothing: validate requested integer quantities, aggregate duplicate sku demand, reject insufficient/missing stock with RangeError, and return a new stock object. applyCharge(order,event) must be immutable/idempotent by event.id; successful events must exactly match order.totalCents and currency before marking paid; failed events do not mark paid; each new event id is recorded once. checkout(order,stock,event) must recompute the trusted total from order.lines, reject a client/order total mismatch, reserve stock, then apply the event, returning {order,stock} without mutating inputs.",
|
|
9
|
+
"grader": "graders/long-horizon.mjs"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"id": "long-tenant-security-integration",
|
|
13
|
+
"fixture": "fixtures/long-horizon",
|
|
14
|
+
"prompt": "Treat this as a long-horizon multi-file task and use durable/fresh-task orchestration if the environment provides it. Repair tenant authorization across src/auth.mjs, src/project-service.mjs, and src/project-api.mjs. Missing inputs deny. Suspended users always deny. Admin may edit a project only inside the same tenant. Members may edit only projects in the same tenant where project.ownerId equals user.id. updateProject must reject unauthorized access with an error whose code is FORBIDDEN, must allow only title and description patch fields, must not mutate project/patch, and must preserve id/tenantId/ownerId. handleProjectUpdate must return {status:200,body:{project}} on success, map FORBIDDEN to 403 with body {error:{code:'FORBIDDEN',message:'Forbidden'}}, map malformed patch input to 400 VALIDATION, and never expose stack/arbitrary error fields.",
|
|
15
|
+
"grader": "graders/long-horizon.mjs"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"id": "long-user-contract-migration",
|
|
19
|
+
"fixture": "fixtures/long-horizon",
|
|
20
|
+
"prompt": "Treat this as a long-horizon multi-file task and use durable/fresh-task orchestration if the environment provides it. Repair the legacy user migration contract across src/user-migration.mjs, src/user-serializer.mjs, src/user-consumer.mjs, and src/user-validation.mjs. migrateUser must return a new object, preserve unrelated fields, preserve existing firstName/lastName, otherwise split trimmed legacy fullName into first token/rest, remove fullName, and keep legacy name when present. serializeUser must preserve id and legacy name while exposing displayName from non-empty user.displayName, otherwise firstName+lastName, otherwise name. validateSerializedUser must require non-null id, non-empty displayName, and if name is present require it to be non-empty. userLabel must prefer displayName but remain backward-compatible with name. Do not mutate inputs.",
|
|
21
|
+
"grader": "graders/long-horizon.mjs"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"id": "long-product-race-cache",
|
|
25
|
+
"fixture": "fixtures/long-horizon",
|
|
26
|
+
"prompt": "Treat this as a long-horizon multi-file task and use durable/fresh-task orchestration if the environment provides it. Repair product mutation state across src/product-state.mjs, src/product-cache.mjs, src/product-service.mjs, and src/product-api.mjs. The reducer must ignore stale success/error actions whose requestId differs from current state.requestId, preserving object identity for stale actions. tagsForProduct must return unique tags in order products, product:<id>, optional category:<categoryId>, optional seller:<sellerId>, rejecting missing id. updateProduct must allow only title/categoryId/sellerId patch fields, be immutable, preserve id, and return {product,tags}. handleProductUpdate must use updateProduct and return {status:200,body:{product},revalidate:tags}; malformed patches return 400 VALIDATION without leaking stack.",
|
|
27
|
+
"grader": "graders/long-horizon.mjs"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"id": "long-full-system-integration",
|
|
31
|
+
"fixture": "fixtures/long-horizon",
|
|
32
|
+
"prompt": "Treat this as a true long-horizon task. You must use the available durable UES workflow with an approved multi-task PLAN, fresh executors, task evidence, integration verification and finalization rather than solving everything in one context. Repair all four broken domains across 15 modules: src/money.mjs, src/inventory.mjs, src/payment.mjs, src/checkout.mjs, src/auth.mjs, src/project-service.mjs, src/project-api.mjs, src/user-migration.mjs, src/user-serializer.mjs, src/user-consumer.mjs, src/user-validation.mjs, src/product-state.mjs, src/product-cache.mjs, src/product-service.mjs, and src/product-api.mjs. Preserve immutability and strict validation throughout. Checkout must use trusted integer-cent totals, all-or-nothing aggregate stock reservation and idempotent exact-currency payment events. Tenant project edits must deny suspended/cross-tenant access, limit patch fields and return sanitized API errors. User migration/serialization must preserve backward compatibility while producing a valid displayName contract without mutating inputs. Product mutation must ignore stale reducer actions, generate stable unique cache tags, restrict patch fields and sanitize API validation errors. All existing hidden requirements of the four domain tasks apply together.",
|
|
33
|
+
"grader": "graders/long-horizon.mjs"
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
}
|