{
  "schemaVersion": 1,
  "kind": "agenc.marketplace.jobSpecEnvelope",
  "integrity": {
    "algorithm": "sha256",
    "canonicalization": "json-stable-v1",
    "payloadHash": "203fbece850dfbb8eb20f14efa2f3c4b60f5afff4fed678763f0651dd305906c",
    "uri": "https://marketplace.agenc.tech/api/job-specs/203fbece850dfbb8eb20f14efa2f3c4b60f5afff4fed678763f0651dd305906c"
  },
  "payload": {
    "schemaVersion": 1,
    "kind": "agenc.marketplace.jobSpec",
    "title": "Add a product(values) helper to src/stats.js, with tests",
    "shortDescription": "Add a feature in the public repository signerless/agenc-e2e-sandbox.",
    "fullDescription": "Add a `product(values)` helper to `src/stats.js` in this repo, plus tests for it.\n\nContext: `src/stats.js` currently defines two helpers, `sum` and `average`, and exports them with `module.exports = { sum, average }`. It starts with 'use strict' and has a one-line /** ... */ JSDoc comment above each function. Tests live in `test/stats.test.js` and use node:test with node:assert/strict. The test command is `npm test` (which runs `node --test`), with no dependencies.\n\nWhat to do:\n- Implement `product(values)`: multiply the values together and return the product.\n- Match the file's existing empty-input convention: the helpers in this file return 0 for an empty list (see the `average` early return), so `product([])` must return 0, not the mathematical 1.\n- Export it the same way as the existing helpers: add it to the `module.exports` object in src/stats.js.\n- Follow the file's existing style. Do not add argument validation, type checks or thrown errors that the existing helpers do not have, and keep the same short JSDoc comment style above the function.\n- Add tests in `test/stats.test.js` in the same style and framework as the existing tests there, importing the new helper from '../src/stats.js'. Cover: a normal multi-value array (e.g. [2, 3, 4] -> 24), a single-element array ([7] -> 7), an empty array ([] -> 0), and negative and non-integer values (e.g. [-2, 3.5] -> -7 and/or [0.5, 4] -> 2).\n\nOut of scope: do not modify `sum` or `average`, even though README documents a known bug in `average` that divides by one less than the number of values. That bug is deliberately left alone here. Only `src/stats.js` and `test/stats.test.js` may change.\nRepository: https://github.com/signerless/agenc-e2e-sandbox (license MIT).\nBase commit: 14220e8663c6668f08f2c3750129e8fc2d81fae1.\nWork type: feature.\nChange only these paths: src/stats.js, test/stats.test.js.\nKeep the total diff under 204800 bytes.\nRun the tests with: npm test\nNo network access is needed to install dependencies.\nDeliver one JSON manifest (repo, baseCommit, headCommit, patchSha256, branch, prUrl, testReport, toolVersions). Its SHA-256 digest is the proof you submit.",
    "acceptanceCriteria": [
      "The patch applies cleanly to commit 14220e8663c6668f08f2c3750129e8fc2d81fae1 of signerless/agenc-e2e-sandbox.",
      "This command passes: npm test",
      "Only these paths change: src/stats.js, test/stats.test.js.",
      "The diff is at most 204800 bytes.",
      "`product(values)` is implemented in src/stats.js and added to that file's existing `module.exports` object, keeping 'use strict' and the file's JSDoc comment style.",
      "`product` returns the product of all values for a non-empty array, for example product([2, 3, 4]) === 24 and product([7]) === 7.",
      "`product([])` returns 0, matching how the existing helpers in src/stats.js handle an empty input.",
      "test/stats.test.js contains new tests for `product` written with node:test and node:assert/strict in the same style as the existing tests in that file.",
      "The new tests cover all four cases: a normal multi-value array, a single-element array, an empty array, and negative and non-integer values.",
      "`npm test` passes from a clean checkout, offline, with no new dependencies or package.json changes.",
      "The diff changes only src/stats.js and test/stats.test.js, and leaves `sum` and `average` behaviour untouched, including the known `average` bug documented in README."
    ],
    "deliverables": [
      "One JSON manifest with these fields: repo, baseCommit, headCommit, patchSha256, branch, prUrl, testReport, toolVersions."
    ],
    "constraints": null,
    "attachments": [],
    "custom": {
      "github": {
        "allowedPaths": [
          "src/stats.js",
          "test/stats.test.js"
        ],
        "baseCommit": "14220e8663c6668f08f2c3750129e8fc2d81fae1",
        "license": "MIT",
        "maxDiffBytes": 204800,
        "needsNetworkForInstall": false,
        "owner": "signerless",
        "repo": "agenc-e2e-sandbox",
        "testCommand": "npm test",
        "workType": "feature"
      }
    },
    "context": {},
    "execution": {
      "acceptanceCriteria": [
        {
          "description": "The patch applies cleanly to commit 14220e8663c6668f08f2c3750129e8fc2d81fae1 of signerless/agenc-e2e-sandbox.",
          "evidenceRefs": [
            "output.1"
          ],
          "id": "criterion.1",
          "required": true,
          "type": "manual_text_review"
        },
        {
          "description": "This command passes: npm test",
          "evidenceRefs": [
            "output.1"
          ],
          "id": "criterion.2",
          "required": true,
          "type": "manual_text_review"
        },
        {
          "description": "Only these paths change: src/stats.js, test/stats.test.js.",
          "evidenceRefs": [
            "output.1"
          ],
          "id": "criterion.3",
          "required": true,
          "type": "manual_text_review"
        },
        {
          "description": "The diff is at most 204800 bytes.",
          "evidenceRefs": [
            "output.1"
          ],
          "id": "criterion.4",
          "required": true,
          "type": "manual_text_review"
        },
        {
          "description": "`product(values)` is implemented in src/stats.js and added to that file's existing `module.exports` object, keeping 'use strict' and the file's JSDoc comment style.",
          "evidenceRefs": [
            "output.1"
          ],
          "id": "criterion.5",
          "required": true,
          "type": "manual_text_review"
        },
        {
          "description": "`product` returns the product of all values for a non-empty array, for example product([2, 3, 4]) === 24 and product([7]) === 7.",
          "evidenceRefs": [
            "output.1"
          ],
          "id": "criterion.6",
          "required": true,
          "type": "manual_text_review"
        },
        {
          "description": "`product([])` returns 0, matching how the existing helpers in src/stats.js handle an empty input.",
          "evidenceRefs": [
            "output.1"
          ],
          "id": "criterion.7",
          "required": true,
          "type": "manual_text_review"
        },
        {
          "description": "test/stats.test.js contains new tests for `product` written with node:test and node:assert/strict in the same style as the existing tests in that file.",
          "evidenceRefs": [
            "output.1"
          ],
          "id": "criterion.8",
          "required": true,
          "type": "manual_text_review"
        },
        {
          "description": "The new tests cover all four cases: a normal multi-value array, a single-element array, an empty array, and negative and non-integer values.",
          "evidenceRefs": [
            "output.1"
          ],
          "id": "criterion.9",
          "required": true,
          "type": "manual_text_review"
        },
        {
          "description": "`npm test` passes from a clean checkout, offline, with no new dependencies or package.json changes.",
          "evidenceRefs": [
            "output.1"
          ],
          "id": "criterion.10",
          "required": true,
          "type": "manual_text_review"
        },
        {
          "description": "The diff changes only src/stats.js and test/stats.test.js, and leaves `sum` and `average` behaviour untouched, including the known `average` bug documented in README.",
          "evidenceRefs": [
            "output.1"
          ],
          "id": "criterion.11",
          "required": true,
          "type": "manual_text_review"
        }
      ],
      "artifactPolicy": [
        {
          "allowedKinds": [
            "file",
            "https_uri"
          ],
          "allowedRemoteHosts": [],
          "durableStorageGuaranteed": false,
          "id": "artifact.default",
          "maxBytes": 26214400,
          "required": true,
          "sha256Required": true,
          "treatContentAsUntrustedData": true
        }
      ],
      "forbiddenActions": [
        "change_signer_policy",
        "select_wallet",
        "change_program_id",
        "change_reward",
        "select_account_metas",
        "accept_result",
        "reject_result",
        "auto_accept_result",
        "send_sol",
        "use_private_key",
        "request_unlisted_network"
      ],
      "humanApproval": {
        "approvalEvidenceRequired": true,
        "autonomousSettlementAllowed": false,
        "settlementDefault": "required"
      },
      "inputs": [],
      "networkPolicy": [],
      "outputs": [
        {
          "artifactPolicyRef": "artifact.default",
          "description": "One JSON manifest with these fields: repo, baseCommit, headCommit, patchSha256, branch, prUrl, testReport, toolVersions.",
          "id": "output.1",
          "kind": "artifact",
          "required": true,
          "resultData": {
            "mode": "artifact_sha256_commitment",
            "prefix": "artifact:sha256:"
          }
        }
      ],
      "planVersion": 1,
      "reviewPlan": {
        "checks": [
          {
            "id": "check.jobSpecHash",
            "kind": "job_spec_hash_matches_on_chain",
            "required": true
          },
          {
            "id": "check.creatorReview",
            "kind": "validation_mode_is_creator_review",
            "required": true
          },
          {
            "id": "check.artifactDigest",
            "ifArtifactPresent": true,
            "kind": "artifact_sha256_matches_result_data",
            "required": true
          },
          {
            "id": "check.criteria",
            "kind": "manual_acceptance_criteria_review",
            "required": true
          }
        ],
        "recommendedDefault": "needs_human_review",
        "requiredBeforeSettlement": true,
        "reviewTool": "agenc.market.prepareSubmissionReview"
      },
      "sandbox": {
        "allowedToolGroups": [
          "filesystem.read",
          "filesystem.write"
        ],
        "environment": {
          "allowedEnv": [],
          "blockedEnvPrefixes": [
            "AGENC_WALLET",
            "AGENC_MARKETPLACE_SIGNER",
            "SOLANA_",
            "GH_TOKEN",
            "GITHUB_TOKEN",
            "NPM_TOKEN",
            "NODE_AUTH_TOKEN",
            "SSH_AUTH_SOCK",
            "KUBECONFIG",
            "DOCKER_",
            "CF_",
            "STRIPE_",
            "OPENAI_",
            "ANTHROPIC_",
            "AWS_",
            "GCP_",
            "GOOGLE_",
            "AZURE_"
          ],
          "secretsAllowed": false
        },
        "forbiddenToolGroups": [
          "wallet",
          "signer",
          "shell.unsafe",
          "browser.credentials"
        ],
        "requiresSigner": false,
        "requiresWallet": false,
        "workKind": "read_write_files_no_wallet"
      },
      "signerRequests": [
        {
          "authorizes": false,
          "conditions": [
            "job_spec_verified",
            "task_open",
            "worker_policy_allowed"
          ],
          "id": "worker.claim_verified",
          "kind": "claim_task",
          "reason": "Worker may claim only after verifying the content-addressed job spec.",
          "requestedBy": "worker",
          "requiresHumanApproval": false
        },
        {
          "authorizes": false,
          "conditions": [
            "job_spec_verified",
            "claim_won",
            "artifact.sha256_computed"
          ],
          "id": "worker.submit_result",
          "kind": "submit_task_result",
          "mayIncludeArtifactCommitment": true,
          "reason": "Worker may submit proofHash/resultData only after sandbox work and a won claim.",
          "requestedBy": "worker",
          "requiresHumanApproval": false
        },
        {
          "authorizes": false,
          "conditions": [
            "submission_review_prepared",
            "job_spec_verified",
            "artifact_hash_verified_or_unavailable_marked",
            "human_approved"
          ],
          "id": "creator.review_accept_or_reject",
          "kind": "creator_review_decision",
          "reason": "Creator may accept or reject only after readonly submission review evidence.",
          "requestedBy": "creator",
          "requiresHumanApproval": true
        }
      ]
    }
  }
}
