Generalizing vs disabling/hiding vs extending the "Is Castrated" field

Making a place to continue this discussion:

1 Like

To summarize the points here:

  • @paul121 was following up on a feature request to hide the field for non-male animals.
  • @mstenta was proposing a follow-up where the state could be modeled via logs - instead of a boolean on the asset.
  • @Symbioquine [I] was arguing that semantically “is castrated” doesn’t make sense for non-male animals, but the concept is still relevant - I think spaying/neutering/sterilizing female animals is relevant in some animal operations such as horses or dogs. We shouldn’t remove the field for female animals, but we should maybe improve the verbiage to make it clearer that it means neutering/sterilization in the more general sense.
2 Likes

I don’t think it should be hidden all together, and agree with @Symbioquine that maybe it just needs a language change.

Maybe this points back to the concept of asset attributes. I think this was @Symbioquine Idea a while ago but a quick a quick search I could not find the discussion. The concept being that assets can have custom assigned attributes that can be set with logs. Animals can be castrated or intact, gates can be open or closed, Fence sections can be energized or off, the possibilities are endless across all assets.

2 Likes

I remember that and think about it often. I would love to come up with a generalized solution to this! And migrate is_castrated to that…

Also wonder if location, inventory, and group computed field logic could be integrated too… since it works similarly (although different data types for each).

2 Likes

I suppose at a minimum we would need some kind of key/value field on logs, along with a new is_attribute_assignment checkbox… or something.

Then it could work similar to is_movement and is_group_assignment.

I think it might be better for it to work a bit more like inventory adjustments - where the log has 0..N - asset_attribute_operations which in turn have 1..N - asset references - along with the data describing the “attribute operation”. e.g. roughly;

{
  "type": "log--activity",
  "id": "...",
  "attributes": {
    "drupal_internal__id": 100,
    "name": "Neuter 2024 Goats",
    "timestamp": "2024-03-30T23:00:00+00:00"
    ...
  },
  "relationships": {
    "asset_attribute_operations": {
        "data": [
            {
              "type": "asset_attribute_operation--asset_attribute_operation",
              "id": "8dee5028-ea58-4a82-973a-b631a8771edc",
            }
        ]
    }
  }
}
{
  "type": "asset_attribute_operation--asset_attribute_operation",
  "id": "8dee5028-ea58-4a82-973a-b631a8771edc",
  "attributes": {
    "drupal_internal__id": 200,
    "operation": "set_boolean",
    "operand_value_0": "is_neutered",
    "operand_value_1": true,
    ...
  },
  "relationships": {
    "asset": {
        "data": [
            {
              "type": "asset--animal",
              "id": "df0e26d5-6b3b-4fe7-976c-2114e1942991",
            },
            {
              "type": "asset--animal",
              "id": "0637d633-d171-474f-b6c6-8b91af4eeeff",
            }
        ]
    }
  }
}
3 Likes

:cricket: :notes:… Anyone?

I think that looks like a great way to do it. :slight_smile:

Yea that could work too @Symbioquine! I need to wrap my head around it a bit more - maybe we can discuss it more on a dev call to brainstorm possibilities.

1 Like

Sounds good. Happy to elaborate more here too - since the format above is a bit terse.

Right now, inventory adjustments are unique in that they have an extra layer of entities - instead of just having the relevant fields directly on the log entity (like movements or group membership changes).

This has some nice consequences;

  • It allows a single log to apply different changes to different assets - e.g. increment one inventory and decrement another as part of the same logical task
  • It generalizes nicely to more complex attribute manipulations without having an ever-expanding set of log fields with special logic tied to them.

I think it might also head a bit in the direction that @jgaehring was alluding to by making the computed attribute operations more explicit. (Correct me if I’m wrong there Jamie.)

Still looking at inventory adjustments, we can consider the quantities for a given (asset, unit, measure) tuple as a stack of operations;

[
  ('reset',     10),
  ('decrement', 5),
  ('increment', 2),
  ('reset',     15),
  ('increment', 7),
  ('increment', 3),
]

yields; asset.inventory[(unit, measure)] = 25

Similarly, for an boolean attribute like is_neutered we could have a stack of operations;

[
  ('set_boolean', false),
  ('set_boolean', true),
]

yields: asset.is_neutered = true

Taking things a bit further, a tags attribute could support some interesting operations;

[
  ('set_list',   ['cute', 'energetic', 'fluffy'])
  ('add_unique', ['troublemaker']),
  ('add_unique', ['troublemaker']),
  ('try_remove', ['cute']),
  ('try_remove', ['willful']),
]

yields: asset.tags = ['energetic', 'fluffy', 'troublemaker']

2 Likes

Make sense! Maybe the only complaint I have is it would result in THREE different approaches to computed values in farmOS… the location/group membership approach, the inventory approach, and then this one. I don’t see any way around that, necessarily… and maybe we can think ahead to merging/refactoring to converge somehow in the future (with a breaking change), but worth noting for now that it adds some mental overhead to understand the differences with all of them.

Agreed. I think the other two could be reasonably represented under this model for a farmOS >V4;

location attribute;

[
  ('set_location', [GreenhouseM, Tray32]),
  ('set_location', [FieldA, BedX]),
]

yields: asset.location = [FieldA, BedX]

geometry attribute;

[
  ('set_geometry', 'POINT(-31.040038615465 39.592143995004)'),
]

yields: asset.geometry = 'POINT(-31.040038615465 39.592143995004)'

group attribute;

[
  ('set_list', [GroupA, GroupB]),
  ('add_unique', [GroupC]),
]

yields: asset.groups = [GroupA, GroupB, GroupC]

2 Likes

Another consequence is that all of this takes the data-model farther from being a simple flat structure that farmers (or anybody really) will tend to grasp quickly/intuitively. The UX would correspondingly need to be improved to compensate.

1 Like

Shouldn’t is casturted simply is sterilized.

Both sexes can/are sterilized.

Heifers that don’t make the top 2% are moved to the stocker pens then the fat cattle yards. We don’t actually sterilize them but we would mark them as such as there vaccine program changes and really are terminal animals at that point

3 Likes

Yea I think in general we’re talking about doing away with the legacy is_castrated field entirely, and replacing it with a more flexible log-based attribute assignment system. So it could be called whatever you want. From there, folks could agree on a convention that makes sense, and I agree “sterilized” seems to be a better term generally.

2 Likes