Skip to content

feat(supertask): skip pretasks already completed against the hashlist#2177

Open
linuxkd wants to merge 1 commit into
hashtopolis:devfrom
linuxkd:feat/skip-completed-pretasks
Open

feat(supertask): skip pretasks already completed against the hashlist#2177
linuxkd wants to merge 1 commit into
hashtopolis:devfrom
linuxkd:feat/skip-completed-pretasks

Conversation

@linuxkd
Copy link
Copy Markdown

@linuxkd linuxkd commented May 28, 2026

Summary

Implements the opt-in dedup requested in #2167. When applying a supertask to a hashlist, optionally skip any pretask whose equivalent attack has already been fully exhausted against that hashlist, instead of re-instantiating a duplicate task that re-runs identical work for zero new coverage.

Opt-in, default OFF — when skipCompleted is not set, behavior is identical to today for every caller (legacy UI, apiv2, and internal runSupertask callers).

Motivation

It's common to apply a refined supertask after an earlier one has finished. Without dedup, every overlapping pretask spawns a fresh task that re-runs an attack already exhausted against the same hashlist. In one recent case, 9 of 40 pretasks in the second supertask were exact duplicates of completed tasks — pure wasted compute.

Match criteria

A Task T is an already-completed equivalent of a pretask spec on hashlist H when ALL hold:

  1. Normalized attackCmd equality (whitespace collapsed/trimmed; flag order not normalized — deliberately conservative)
  2. Identical fileId set (T via FileTask vs pretask via FilePretask)
  3. T.crackerBinaryId == resolved binary id AND T.crackerBinaryTypeId == type id
  4. T.keyspace > 0 AND T.keyspaceProgress >= T.keyspace (fully exhausted; partials never match)
  5. T belongs to a TaskWrapper whose hashlistId == H

Archived-but-exhausted tasks do count as matches.

API response shape

apiv2 helper/createSupertask gains an optional skipCompleted bool. When set, the response adds a top-level JSON:API meta.skippedPretasks array alongside the unchanged TaskWrapper data resource:

{
  "data": { "...": "TaskWrapper" },
  "meta": { "skippedPretasks": [ { "pretaskId": 12, "matchingTaskId": 88 } ] }
}

When every pretask is skipped, no TaskWrapper is created and a meta-only response is returned:

{ "taskWrapperId": null, "skippedPretasks": [ "..." ] }

Fully backward-compatible: the meta member is only added when skipCompleted is requested, getResponse() stays "TaskWrapper", and the new meta member is documented in the actionPost PHPDoc (feeds the OpenAPI description).

What's in this PR

  • TaskUtils::findCompletedEquivalent() (+ normalizeAttackCmd, getFileIdsOfTask, getFileIdsOfPretask)
  • SupertaskUtils::runSupertask() gains $skipCompleted; returns ['taskWrapper' => …, 'skippedPretasks' => …]; suppresses the empty wrapper when all are skipped
  • apiv2 base-class seam: getOneResource($extraMeta) + overridable getExtraMeta(), threaded through processPost (additive, non-breaking)
  • helper/CreateSupertaskHelperAPI: skipCompleted field + meta wiring
  • Legacy supertask-apply forms get a "skip completed" checkbox
  • phpunit: 10 unit tests for findCompletedEquivalent (match + every exclusion + whitespace normalization + archived), 3 e2e tests for runSupertask skip behavior

Testing

  • phpstan level 4 clean on src/inc/apiv2 + ci/phpunit
  • Full phpunit suite: 238 tests / 2354 assertions, 0 failures/errors
  • New tests: 19 tests / 204 assertions green
  • Live apiv2: ci/apiv2/test_supertask.py passes
  • Manual end-to-end through the real Angular GUI + a live CPU agent: applied a 2-pretask supertask with "skip completed" to a hashlist where one pretask was already exhausted → the duplicate pretask was skipped, only the new pretask instantiated and cracked the hash; verified the all-skipped meta-only response too (screenshots on [FEATURE]: Skip pretasks already completed against the target hashlist when assigning a supertask #2167)

Follow-ups (intentionally out of scope here)

  • Angular web-ui checkbox: separate PR to hashtopolis/web-ui (ready, opened right after this)
  • Pretask→hashlist direct apply: no clean apiv2 home today (legacy path is the entangled restricted-user task-create branch); findCompletedEquivalent is reusable and ready to power it later

Refs #2167

Add an opt-in option to skip pretasks whose equivalent attack has already
been fully exhausted against the target hashlist when applying a supertask,
avoiding duplicate tasks that re-run identical work for zero new coverage.
Default off preserves existing behavior for all callers.

- TaskUtils::findCompletedEquivalent matches a pretask spec to a fully
  exhausted Task on the hashlist (normalized attackCmd, fileId set,
  cracker binary+type, keyspaceProgress >= keyspace > 0; archived counts)
- SupertaskUtils::runSupertask gains $skipCompleted; returns the created
  TaskWrapper plus the list of skipped pretasks, and creates no wrapper
  when every pretask is skipped
- apiv2 createSupertask gains a skipCompleted flag and reports skipped
  pretasks via the top-level JSON:API meta member (TaskWrapper response
  unchanged when the flag is off)
- legacy supertask-apply forms get a "skip completed" checkbox
- phpunit unit and e2e tests covering the match, every exclusion, and the
  runSupertask skip flow

Refs hashtopolis#2167
@linuxkd
Copy link
Copy Markdown
Author

linuxkd commented May 28, 2026

Web-ui follow-up PR (the Angular checkbox referenced above): hashtopolis/web-ui#688

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant