Comments can move between rules in two ways: automatically (via Soft Redirect on child→parent satisfies relationships) or manually (via the admin Move Comment action). In both cases, the original rule the commenter actually targeted is preserved on the review row for the life of the record.
Every re-parented comment carries two parallel records of where it originally came from:
Human-readable prefix in the comment text:
[Re: CNTR-00-001028]The commenter's original text...
1 2
or, when an admin moves the comment retroactively:
[Moved from CNTR-00-001028: typo'd rule id]The original comment text...
1 2
Triagers reading the thread see this in line; it's a prose artifact.
original_commentable_id — a machine-queryable column on reviews that holds the BaseRule id of the comment's first target. Set once on the first re-parenting and never overwritten, so even if a comment gets moved a second time the field still points at where the commenter originally posted.
The two channels serve different audiences:
Triagers reading inline → the prose prefix.
Disposition exports, audit reports, "which rules attracted comments on the source side" queries → the column.
Soft redirect (Reviewbefore_create callback): when a comment on a child rule is rewritten to point at the parent control, the callback sets original_commentable_id to the child rule's id.
Admin move-to-rule (Review#move_to_rule!): when an admin moves a comment from rule A to rule B, the model sets original_commentable_id to A — but only if it isn't already set. Re-moves preserve the first move's provenance so the audit trail always points back to the commenter's original target, not an intermediate stop.
JSON-archive export: the export serializer carries original_commentable_id (mapped through to the destination instance's rule on re-import) so cross-instance backup/restore preserves the provenance.
Import: ReviewBuilder remaps the field through the archive's rule_id → new local BaseRule.id map (@rule_id_map), same as addressed_by_rule_id and the parent FK refs in Pass 2.
Comment Provenance
Comments can move between rules in two ways: automatically (via Soft Redirect on child→parent satisfies relationships) or manually (via the admin Move Comment action). In both cases, the original rule the commenter actually targeted is preserved on the review row for the life of the record.
The provenance pair
Every re-parented comment carries two parallel records of where it originally came from:
Human-readable prefix in the comment text:
2
or, when an admin moves the comment retroactively:
2
Triagers reading the thread see this in line; it's a prose artifact.
original_commentable_id— a machine-queryable column onreviewsthat holds the BaseRule id of the comment's first target. Set once on the first re-parenting and never overwritten, so even if a comment gets moved a second time the field still points at where the commenter originally posted.The two channels serve different audiences:
Where it gets set
Reviewbefore_createcallback): when a comment on a child rule is rewritten to point at the parent control, the callback setsoriginal_commentable_idto the child rule's id.Review#move_to_rule!): when an admin moves a comment from rule A to rule B, the model setsoriginal_commentable_idto A — but only if it isn't already set. Re-moves preserve the first move's provenance so the audit trail always points back to the commenter's original target, not an intermediate stop.Where it shows up
original_commentable_id(mapped through to the destination instance's rule on re-import) so cross-instance backup/restore preserves the provenance.ReviewBuilderremaps the field through the archive'srule_id→ new localBaseRule.idmap (@rule_id_map), same asaddressed_by_rule_idand the parent FK refs in Pass 2.Why both prefix and column
The prose prefix is what a triager sees when scrolling a thread; the column is what an export reader queries. Either alone has failure modes:
Together they cover both reading paths.
Related