Skip to content

feat: let a solution name the Task its module work contexts are minted under (Gateway.ForTask) - #43

Closed
met-obin-ai wants to merge 2 commits into
codefly-dev:mainfrom
met-obin-ai:mohamed/final/fortask-2026-09-24
Closed

met-obin-ai wants to merge 2 commits into
codefly-dev:mainfrom
met-obin-ai:mohamed/final/fortask-2026-09-24

Conversation

@met-obin-ai

Copy link
Copy Markdown

Why

Gateway.ForModule mints every module Work Context under a new Task: ask.TaskID = uuid.NewString() for each mint, and each viewer request gets a new gateway and cache. Some modules only let a caller read work admitted under the caller's own Task. A durable task runtime, for example, answers Read with NOT_FOUND unless tenant, owner and boundary match. With such a module, a later request can't read work that an earlier request started. So polling a run, reloading a page, and asking the same question again all get a 404.

What changed

  • 499bd4b feat: let a solution name the Task its module work contexts are minted under. This is an additive API. ForModule is unchanged: its cache-key bytes are the same, it still mints a new taskId each time, and it sends no ttlSeconds.
    type Task struct { ID string; TTLSeconds int32 }
    func (g *Gateway) ForTask(ctx context.Context, task Task, audience string, scopes ...Scope) (*Gateway, error)
    • Task.ID is sent to accounts' StartTask exactly as given, as taskId. It must be a hyphenated UUID, the form accounts validates (buf.validate string.uuid). Any other value, including an empty id, is refused before a request is made.
    • Task.ID and Task.TTLSeconds are part of the cache identity, so two Tasks never share a capability. One Task's ask still mints once per request.
    • A non-zero Task.TTLSeconds is sent as ttlSeconds, a field StartTaskWorkContextRequest already has. Zero sends nothing.
    • The org, session and bearer stay the viewer's, as with ForModule.
    • The README documents ForTask, and ForModule's doc comment says when to use ForTask instead.
  • 9081020 test: use structural fixture names instead of a business genre. solution_test.go renamed a consumed module and scope alpha/items. Values and assertions are unchanged.

4 files, +353 −22 (README.md, solution.go, solution_test.go, work_context_task_test.go).

Tests

New tests are in work_context_task_test.go: TestForTaskSendsTheNamedTaskVerbatim, TestForTaskNeverSharesAContextBetweenTasks, TestForTaskReusesTheContextOfTheSameTask, TestForTaskRefusesATaskIDAccountsWouldNot, TestForTaskSendsTheTTLWhenGiven, TestForModuleStillNamesAFreshTaskPerMint.

Mutations of solution.go, each run against this suite (all red, and green again once restored):

  • Always drawing a new task id, even for a named Task, fails …SendsTheNamedTaskVerbatim and …NeverSharesAContextBetweenTasks.
  • Dropping the UUID shape check fails …RefusesATaskIDAccountsWouldNot.
  • Not sending TTLSeconds fails …SendsTheTTLWhenGiven.
  • Leaving the Task id out of the cache key fails …NeverSharesAContextBetweenTasks.

These are the go.yml steps, run locally with go 1.27.1 (the workflow uses 1.27.0 from go.mod):

step 9081020 (this branch) merged with current main (8da58cd, merges without conflicts)
go mod download && go mod verify all modules verified all modules verified
go test -race ./... -count=1 -timeout=5m 105 top-level + 125 subtests passed, 0 failed, 0 skipped 150 top-level + 149 subtests passed, 0 failed, 0 skipped
go vet ./... clean clean
gofmt -l ./*.go empty empty

Not verified

  • The suite is hermetic: it checks wire shapes and refusals. Accounts accepting a reused task_id was measured separately against a live host (two mints with the same task_id and different nonces), outside this suite.
  • ttlSeconds has never been sent to a live Accounts.
  • The branch is based on v0.0.11 (89e1aea) and is 9 commits behind main. It merges cleanly, and the merged tree passes the table above, but the branch has not been merged forward, so the commit shas stay stable for a downstream consumer that pins this change as a pseudo-version.

…d under

ForModule draws a fresh taskId for every mint. A module that fences reads by
the Task a capability was minted under (a durable task runtime reads and lists
only the tasks admitted under the caller's own Task) therefore refuses every
read a later viewer request makes of work an earlier request started: the
second request's capability names a different Task.

Gateway.ForTask(ctx, Task{ID, TTLSeconds}, audience, scopes...) is ForModule
under a Task the solution names:

- Task.ID is sent to accounts' StartTask verbatim as taskId (accounts signs
  it as given and accepts the same id again on a later mint). It must be a
  hyphenated UUID, the form accounts validates (buf.validate string.uuid);
  anything else, including an empty id, is refused before any request.
- Task.ID and Task.TTLSeconds are part of the cache identity, so two Tasks
  never share a capability; one Task's ask still mints once per request.
- Task.TTLSeconds, when non-zero, is sent as ttlSeconds, which
  StartTaskWorkContextRequest already carries; zero sends nothing.
- The org and session stay the viewer's, exactly as for ForModule.

ForModule is unchanged: same cache key bytes, a fresh taskId per mint, no
ttlSeconds on the wire. Additive API; no consumer breaks.
solution_test.go still named its second consumed module/scope after a
document genre and business line (billing/invoices), the exact pattern
IMPLEMENTER-RULES.md rule 3 forbids in a platform repo (never names a
solution or a customer) and that a sibling commit (fb851fd, on the old
pre-rebase fortask branch) already cleaned up elsewhere in this same
file. That commit's patch does not apply here (this branch's
solution_test.go has diverged), so this reapplies the identical
mapping (billing -> alpha, invoices -> items) by hand at every site.
Values and assertions are unchanged; no test is weakened.
@antoinetoussaint-byte

Copy link
Copy Markdown
Contributor

Superseded by e80369a: Gateway.ForModule and the accounts StartTask mint are deleted; minting goes through the authority (IssueForModule). Closed in the 2026-10-27 clean-up on the owner's instruction.

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.

2 participants