feat(young-persons): age at engagement, the section 3A Schedule bar, and section 7 hours the adult engine cannot express (#1877) - #1882
Merged
Dev1822 merged 1 commit intoAug 28, 2026
Conversation
@MOHITKOURAV01 is attempting to deploy a commit to the Dev's projects Team on Vercel. A member of the Team first needs to authorize it. |
…tion 7 hours the adult engine cannot express (Dev1822#1877) The employee model carries a date of birth and nothing compares it against the date of engagement. `workingHoursCompliance.js` — the module that would notice — implements the adult Factories Act limits: nine hours a day, forty-eight a week, the section 59 double rate. An adolescent rostered for nine hours passes every check in this product today. There is no currency anywhere in this feature, and that is the design rather than an omission. An underage engagement has no compensable amount. Section 14's punishment is imprisonment and a fine on conviction — a criminal penalty, not a liability that accrues — and a rupee figure in this module's output would be summed into a compliance provision by the first report that read it, stating in a number that employing a child has a price. `assertNoAmounts` walks any result for a money-shaped key, the assessment endpoint runs it on the way out and fails with a 500 rather than returning one, and the test suite asserts it over every shape the engine produces. Two prohibitions rather than one. A child is anybody below fourteen and section 3's bar is total — any occupation or process, with only the family enterprise and audio-visual artist provisos, both conditional on schooling and both claims about a relationship rather than job titles, so an unevidenced claim is a finding and the register refuses to record one. An adolescent is fourteen to under eighteen and section 3A's bar is by Schedule. Collapsing the two into one "underage" test would either bar lawful adolescent work or permit a child. Classification is a function of a date and is never stored. Somebody engaged lawfully as an adolescent turns eighteen during their employment and the section 7 limits fall away on that day — not at the end of the month and not when somebody updates a field. `assessPerson` recomputes per day, so a roster straddling the birthday is measured against these limits before it and against the adult engine's after. Section 7's day is six hours *including* the interval and any waiting time, which is the part people misread: six hours of work plus the one-hour interval the Act requires is a seven-hour day and is over. So the day is measured from first start to last end rather than by adding the spells. And overtime is not a rate here. `overtimeTreatment` states the precedence in code — for anybody under eighteen the section 59 computation does not apply, because there is no rate at which the hour becomes lawful. It returns a sentence and never a figure.
MOHITKOURAV01force-pushed
the
feat/1877-adolescent-employment
branch
from
August 28, 2026 16:47
3931689 to
307f58aCompareUh oh!
There was an error while loading. Please reload this page.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
This PR implements the Child and Adolescent Labour (Prohibition and Regulation) Act, 1986 — the age at engagement, the section 3A Schedule bar, and the section 7 hours that
workingHoursCompliance.jscannot express.utils/adolescentEmployment.js): age classification as a function of a date, the two prohibitions kept separate, the section 7 spell/interval/day/night/overtime/weekly-day-off limits,overtimeTreatmentas an explicit precedence rule, andassertNoAmountsas a guard.adolescentEmployment.model.js):AgeRecord(date of birth and what it rests on),YoungPersonRegister(the section 11 register),EmploymentFinding(no amount field),EmploymentAssessment(counts, with the Schedule snapshotted)./api/young-persons/rules,/age-records,/register,/register/:id/days,/assessment,/findings,/assessments.YoungPersonsRegister.jsx): prohibited engagements as a blocking banner, then the register, then the section 7 limits in force. No currency anywhere on it.The design point: there is no money in this feature
An underage engagement has no compensable amount. Section 14's punishment is imprisonment and a fine on conviction — a criminal penalty, not a liability that accrues. A rupee figure here would be summed into a compliance provision by the first report that read it, and the resulting line would state, in a number, that employing a child costs a known amount.
So:
assertNoAmountswalks any result for a money-shaped key and is exported for the suite;GET /assessmentruns it on the way out and returns 500 rather than a payload with a price in it;EmploymentFindinghas no amount, cost, penalty or exposure field, andEmploymentAssessmentcarries counts of people;Two prohibitions, not one
A child is anybody below fourteen and section 3's bar is total — any occupation or process, with only the family-enterprise and audio-visual-artist provisos. Both are claims about a relationship and about schooling rather than job titles, so an unevidenced claim is a finding and the register refuses (422) to record one. The family exception does not reach a hazardous occupation.
An adolescent is fourteen to under eighteen and section 3A's bar is by Schedule — mines, inflammable substances, explosives, and the hazardous processes incorporated by reference from section 2(cb) of the Factories Act. Outside the Schedule the engagement is permitted, under section 7.
Collapsing the two into one "underage" test would either bar lawful adolescent work or permit a child.
Classification is a date, and it moves
Somebody engaged lawfully as an adolescent turns eighteen during their employment and the section 7 limits fall away on that day. So classification is computed by
classifyOn(date)and never persisted —assessPersonrecomputes it per worked day, and a roster straddling the birthday is measured against these limits before it and against the adult engine's after.completedYearsuses calendar arithmetic rather than days ÷ 365.25, because a leap-day birthday is exactly the case where a day is the whole question.The six-hour day is inclusive
Section 7(2) caps the day including the interval and any waiting time. Six hours of work plus the one-hour interval the Act requires is a seven-hour day and is over the limit. So
assessDaymeasures from first start to last end rather than summing the spells, and adds recorded waiting time.Overtime is not a rate
workingHoursCompliance.jsanswers an excess hour by computing the section 59 double rate. Section 7(4) prohibits overtime for a young person outright.overtimeTreatmentstates that precedence in code and is carried on every person in the payload, so a caller cannot reach the wrong engine by default. It returns a sentence, never a figure.Related Issue
Component(s) Affected
backend/)frontend/)Type of Change
Testing Performed
utils/adolescentEmployment.js, all passing.assertNoAmountsasserted to return[]overassessEstablishment,assessDayandovertimeTreatmentresults, and asserted to find a plantedamount/penaltykey so the guard itself is not vacuous.estimatedPenalty,exposureortotalLiability.DAY_EXCEEDS_LIMITbreach the day before somebody turns eighteen and not a finding the day after.permissions.routeCoveragepasses for the new router (the unrelated failures in that suite are pre-existing onmain).Checklist
Merge behaviour
This PR touches five shared wiring files — the permission vocabulary, the audit vocabulary,
app.js, the route-mounting test, and the frontend navigation registry. Its blocks are placed at their own anchor in each of those files rather than beside the most recently added neighbour, so that this and the sibling PRs in the same batch do not collide on the same hunk.Verified by merging all of them onto
mainin forward and shuffled order: no conflicts either way,node --checkclean on the combined result, all five routers mounted, andpermissions.routeCoveragegaining its new cases with no new failures.