You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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:
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
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_task with no source supplied is self
the dispatcher still produces catalog/assigned (copied from the duty) —
already covered by test/dispatch.test.ts / test/dispatch-wiring.test.ts
the assignment fan-out still produces assigned — already covered by test/assignment-fanout.test.ts
Found while implementing #50 (flip
duly_duty.source's default toself), whosefile surface was
src/objects/duty.object.tsonly. Filed rather than fixed —src/objects/task.object.tsis 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 identicalthree-option select, with the identical comment calling it the caliber field
metrics are allowed to read — and the identical
default: truesitting oncatalog:Unlike the assignment fan-out (which writes
duly_task.sourceexplicitly —see below), the dispatcher (
src/jobs/dispatch.plan.ts:382,source: duty.source ?? '') also always writes it explicitly, copied from theparent duty. So the dispatched-task path is not exposed.
But
src/security/permission-sets.tsgrants theduly_memberpositionduly_task: { allowCreate: true, allowRead: true, allowEdit: true, readScope: 'own', writeScope: 'own' }— a member can create their ownduly_taskdirectly, not just via dispatch.
src/views/task.view.tsputssourceonseveral columns/tooltips but defines no create form that stamps it, so a
hand-created task falls back to the field default:
catalog. That is thesame 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
task.object.tsvsduty.object.ts) — outside A hand-created duty defaults tosource: 'catalog', so a self-declared duty is born scoreable #50'sclaimed file surface, and the PM adjudication comment on A hand-created duty defaults to
source: 'catalog', so a self-declared duty is born scoreable #50 scoped onlythe duty object, not stating a position on the task-side twin.
duly_taskhas no analogue toduly_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 to
source: '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: thefan-out (
src/flows/assignment.flow.ts) never creates aduly_dutyrow atall — both its
create_recordnodes targetobjectName: '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
duly_taskwith nosourcesupplied isselfcatalog/assigned(copied from the duty) —already covered by
test/dispatch.test.ts/test/dispatch-wiring.test.tsassigned— already covered bytest/assignment-fanout.test.tssource: 'catalog', so a self-declared duty is born scoreable #50 added intest/invariants.test.ts