Repository navigation
duly_task.source carries the same catalog-default bug as duly_duty.source, and a member can hand-create a duly_task #55
Description
Found while implementing #50 (flip duly_duty.source's default to self), whose
file surface was src/objects/duty.object.ts only. Filed rather than fixed —
src/objects/task.object.ts is a different object with its own claim risk,
and the PM adjudication comment on #50 scoped only the duty object.
What
duly_task.source (src/objects/task.object.ts) declares the identical
three-option select, with the identical comment calling it the caliber field
metrics are allowed to read — and the identical default: true sitting on
catalog:
source: Field.select({
label: 'Source',
required: true,
options: [
{ label: 'Role catalog', value: 'catalog', color: '#16515F', default: true },
{ label: 'Assigned by manager', value: 'assigned', color: '#8C6512' },
{ label: 'Self-declared', value: 'self', color: '#576B73' },
],
}),Unlike the assignment fan-out (which writes duly_task.source explicitly —
see below), the dispatcher (src/jobs/dispatch.plan.ts:382,
source: duty.source ?? '') also always writes it explicitly, copied from the
parent duty. So the dispatched-task path is not exposed.
But src/security/permission-sets.ts grants the duly_member position
duly_task: { allowCreate: true, allowRead: true, allowEdit: true, readScope: 'own', writeScope: 'own' } — a member can create their own duly_task
directly, not just via dispatch. src/views/task.view.ts puts source on
several columns/tooltips but defines no create form that stamps it, so a
hand-created task falls back to the field default: catalog. That is the
same inversion #50 just fixed on the duty side — a self-declared task would be
born into the governed, scoreable set.
Why filed separately rather than fixed alongside #50
- Different file (
task.object.tsvsduty.object.ts) — outside A hand-created duty defaults tosource: 'catalog', so a self-declared duty is born scoreable #50's
claimed file surface, and the PM adjudication comment on A hand-created duty defaults tosource: 'catalog', so a self-declared duty is born scoreable #50 scoped only
the duty object, not stating a position on the task-side twin. - Not mechanically identical in consequence:
duly_taskhas no analogue to
duly_catalog_sync's cadence rewrite, so the blast radius is scoring-only,
not scoring-plus-cadence-corruption. Worth its own look rather than a
drive-by copy of A hand-created duty defaults tosource: 'catalog', so a self-declared duty is born scoreable #50's diff.
Correction to #50's stated premise, surfaced along the way
#50 and its adjudication comment describe "the assignment fan-out" as a
producer of a governed duty with source: 'assigned'. It isn't: the
fan-out (src/flows/assignment.flow.ts) never creates a duly_duty row at
all — both its create_record nodes target objectName: 'duly_task'
directly. It writes source: 'assigned' on the task, unconditionally,
so it is unaffected by either this finding or #50. Doesn't change either
fix; noted because the premise as stated is imprecise and this is the
object where it actually applies.
Suggested acceptance sketch
- a hand-created
duly_taskwith nosourcesupplied isself - the dispatcher still produces
catalog/assigned(copied from the duty) —
already covered bytest/dispatch.test.ts/test/dispatch-wiring.test.ts - the assignment fan-out still produces
assigned— already covered by
test/assignment-fanout.test.ts - an invariant test pins the direction, next to the one A hand-created duty defaults to
source: 'catalog', so a self-declared duty is born scoreable #50 added in
test/invariants.test.ts
Activity
Flip duly_task.source default from catalog to self (#55)
os-warren commentedon Sep 1, 2026
PM folded this into #54 (the #50 PR) rather than dispatching it separately — the fix is one line adjacent to #50's, and
task.object.tswas unowned this round.default: truemoved fromcatalogtoselfonduly_task.sourcein that PR, with the three producers (dispatcher, assignment fan-out, member hand-create) verified rather than assumed. See PR #54 for the full writeup; it now carriesFixes #55.Generated by Claude Code
Default source to self on duly_duty and duly_task (#54)