{
  "endpoint": "https://otherworldlabs.com/chore-chart-counted-and-earned-by-person/api.json",
  "page": "https://otherworldlabs.com/chore-chart-counted-and-earned-by-person/",
  "what_it_answers": "For a grid of up to six people and up to ten chores, where the reader types a count in each cell and a value against each chore, what each chore came to across everybody, what each person earned out of their own cells alone, one grand total in each unit, and the difference between the two ways of adding the grid. It keeps an amount of money apart from a number of points as two totals and never adds them into one, it keeps a typed zero apart from a cell left empty, and it divides nothing: no total is allocated to anybody and no share and no percentage is computed anywhere.",
  "shape": "A static document, not a service. There is no request to make and nothing is posted anywhere: this file is the engine written out so that an agent re-doing the arithmetic gets the same answer the page gets. The page's own flat answer is the function apiOutputs in its core script, and every output named below is a field of it.",
  "units": "Whole counts, amounts of money to two decimal places, and points to two decimal places. Nothing else: this engine computes no duration, no area, no weight, no rate, no ratio and no percentage, and there is no hour, no minute, no date and no percentage figure anywhere in it.",
  "the_page_supplies_no_figure": "Every input is the reader's own: how many columns and how many rows the chart has, the label on each column, the name of each chore, what one of that chore is worth, whether that value is an amount of money or a number of points, and the count in each cell. The page supplies no chore, no chore list, no chore-by-age table, no difficulty rating, no frequency and no duration, and the only chore words anywhere on it are the ones the reader types. It supplies no amount: no allowance, no pocket money, no pay rate, no points scale and no typical or average figure, and it makes no claim about what any chore is worth, what is usual or what anybody else does. It gives no parenting, discipline, reward, punishment, incentive, motivation, screen-time or consequence advice and makes no claim about chores and responsibility, chores and character or chores and outcomes. It makes no developmental, educational, psychological, behavioural, health or safety claim and says nothing about what anyone of any age can, should or should not do. It makes no employment, wage, minimum-wage, tax, benefit or child-labour statement of any kind. It prints no verdict, grade, star, rank, league table or comparison between people, the rows sitting in the order typed and the columns in the order labelled. And it asks for no name, no age, no date of birth, no school, no class, no year group, no photo and no date of any kind: a column carries a LABEL, there is no other field about a person anywhere in the state, and the page's own test suite asserts the absence of every one of those fields rather than the builder intending it.",
  "state": {
    "shape": "{ peopleCount, people: [ { label }, ... ], choreCount, chores: [ { name, value, unit, count1, count2, count3, count4, count5, count6 }, ... ] }",
    "the_grid": "The chart is chores by people. A chore member carries one cell per person as count1 to count6, count<N> being the cell in column N, because a chore row is the unit a reader fills in and a value belongs to a row rather than to a cell.",
    "peopleCount_and_choreCount": "Integers. The people count is read inside 1 to 6 and the chore count inside 1 to 10. Out of range in EITHER direction is read as not read at all, and never pulled to the nearest value the control offers. When neither spelling supplies a readable count, the length of the list itself is used where the list has members and the minimum of the range where it has none; the page's own controls ship at 2 and 3 and cannot be blank, so that branch belongs to the second spelling below.",
    "a_label": "Free text, up to 24 characters, trimmed of its outer whitespace and of repeated whitespace inside it. Blank is allowed, and a blank or whitespace-only label is headed with the furniture word Person followed by that column's number. A label is the only field about a person this engine has: there is no name, age, date of birth, school, class, year group, photo or date in the state, and nothing is sent anywhere.",
    "a_chore_name": "Free text, up to 40 characters, trimmed the same way. Blank is allowed, and a blank or whitespace-only name is headed with the furniture word Chore followed by that row's number. The engine supplies no chore name of its own in any state.",
    "a_value": "A number from 0 to 999.99, read as whole hundredths of its unit. Blank is NOT read as zero: a row with no value has no amount, and its row total says that no value is typed rather than printing a figure it has not got. A figure outside the range in either direction is read as not typed. A figure finer than a hundredth is rounded to the nearest hundredth once, before it is multiplied by anything.",
    "a_unit": "The string money or the string points. Any other string, including the empty string, is a unit this engine did not read: the row's amount is then placed in NEITHER total and the row says so. The page's own control offers only the two and ships with money chosen, so a state with no unit is not reachable from the page itself; it is reachable from this endpoint and is answered rather than guessed at.",
    "a_cell": "A whole number from 0 to 99. Blank is not zero in the record: a blank cell and a typed zero both add nothing to every total, and the engine keeps them apart, reporting how many cells carry a typed zero and how many carry nothing. A figure outside the range in either direction is read as not typed, and a fraction is rounded to the nearest whole number once before the range is tested.",
    "columns_and_rows_beyond_the_count": "A member of either list beyond the count the engine read is in no figure at all. Lowering a count does not clear what was typed in the rows or the columns beyond it, on the page or in this endpoint.",
    "the_second_spelling": "A caller may hand in `people` as a plain list of label strings rather than objects, and a chore as carrying a `counts` array - one entry per person, in column order - rather than count1 to count6. That is the shape the workbook sold beside this page is read against at S13: the workbook's chores sheet IS that spelling, one row a chore with a cell per person. Nothing is added by it, no state is reachable through it that the controls cannot reach, and the page's own test suite asserts that the two spellings answer identically at every swept state. With neither count supplied the lengths of the two lists are the counts.",
    "nothing_is_divided": "There is no typed total anywhere in this state and nothing in this engine divides, allocates or shares out a figure. Every total it reports is built UP out of the cells, which is why there is no pot, no share, no weight and no percentage in the shape above."
  },
  "inputs": [
    {
      "name": "peopleCount",
      "label": "How many people the chart has",
      "type": "integer",
      "control": "peopleCount",
      "offered": { "min": 1, "max": 6, "step": 1 },
      "blank_means": "no count read; the length of the people list is used where it has members, and 1 where it has none",
      "note": "The page's control ships at 2 and offers 1 to 6."
    },
    {
      "name": "people[].label",
      "label": "The label on a column",
      "type": "text",
      "control": "label0 to label5",
      "offered": { "maxLength": 24 },
      "blank_means": "a blank label, headed with the furniture word Person and that column's number",
      "note": "The only field about a person anywhere in this engine. An initial or a nickname is enough, and nothing is asked for beyond it."
    },
    {
      "name": "choreCount",
      "label": "How many chores the chart has",
      "type": "integer",
      "control": "choreCount",
      "offered": { "min": 1, "max": 10, "step": 1 },
      "blank_means": "no count read; the length of the chores list is used where it has members, and 1 where it has none",
      "note": "The page's control ships at 3 and offers 1 to 10."
    },
    {
      "name": "chores[].name",
      "label": "What a chore is called",
      "type": "text",
      "control": "chore0 to chore9",
      "offered": { "maxLength": 40 },
      "blank_means": "a blank name, headed with the furniture word Chore and that row's number",
      "note": "The page supplies no chore name in any state."
    },
    {
      "name": "chores[].value",
      "label": "What one of that chore is worth",
      "type": "number",
      "control": "value0 to value9",
      "offered": { "min": 0, "max": 999.99, "step": 0.01 },
      "blank_means": "no value: that row's amount is not computed and its row total says so",
      "note": "Blank is not read as zero. A typed zero is a figure the reader typed and foots as zero."
    },
    {
      "name": "chores[].unit",
      "label": "What that value is in",
      "type": "enum",
      "control": "unit0 to unit9",
      "offered": { "values": ["money", "points"] },
      "blank_means": "a unit this engine did not read: that row's amount is in neither total",
      "note": "The control ships with money chosen and offers only the two, so a blank unit is reachable from this endpoint and not from the page."
    },
    {
      "name": "chores[].count1",
      "label": "The cell in column 1 of that chore's row",
      "type": "integer",
      "control": "cellP1_0 to cellP1_9",
      "offered": { "min": 0, "max": 99, "step": 1 },
      "blank_means": "a cell left empty, which adds nothing and is kept apart from a typed zero",
      "note": "count2 to count6 are the same input in columns 2 to 6, with the same range and the same reading."
    },
    {
      "name": "chores[].count2",
      "label": "The cell in column 2 of that chore's row",
      "type": "integer",
      "control": "cellP2_0 to cellP2_9",
      "offered": { "min": 0, "max": 99, "step": 1 },
      "blank_means": "a cell left empty",
      "note": "as count1."
    },
    {
      "name": "chores[].count3",
      "label": "The cell in column 3 of that chore's row",
      "type": "integer",
      "control": "cellP3_0 to cellP3_9",
      "offered": { "min": 0, "max": 99, "step": 1 },
      "blank_means": "a cell left empty",
      "note": "as count1."
    },
    {
      "name": "chores[].count4",
      "label": "The cell in column 4 of that chore's row",
      "type": "integer",
      "control": "cellP4_0 to cellP4_9",
      "offered": { "min": 0, "max": 99, "step": 1 },
      "blank_means": "a cell left empty",
      "note": "as count1."
    },
    {
      "name": "chores[].count5",
      "label": "The cell in column 5 of that chore's row",
      "type": "integer",
      "control": "cellP5_0 to cellP5_9",
      "offered": { "min": 0, "max": 99, "step": 1 },
      "blank_means": "a cell left empty",
      "note": "as count1."
    },
    {
      "name": "chores[].count6",
      "label": "The cell in column 6 of that chore's row",
      "type": "integer",
      "control": "cellP6_0 to cellP6_9",
      "offered": { "min": 0, "max": 99, "step": 1 },
      "blank_means": "a cell left empty",
      "note": "as count1."
    },
    {
      "name": "chores[].counts",
      "label": "The cells of that chore's row, as one list",
      "type": "array of integer or null",
      "control": "none; the second spelling only",
      "offered": { "min": 0, "max": 99, "step": 1 },
      "blank_means": "an entry that is null, blank or absent is a cell left empty",
      "note": "The workbook's spelling of one row. Where it is present it is read instead of count1 to count6, entry by entry in column order."
    }
  ],
  "rounding": {
    "what_is_rounded": "A typed value, once, to the nearest hundredth of its unit, before it is multiplied by anything; and a typed count, once, to the nearest whole number, before its range is tested. Nothing else in this engine rounds, because nothing else in it needs to: every amount is held as a whole number of hundredths from that point on, every product is a whole count multiplied by a whole number of hundredths, and every total is an integer sum of those. There is no half-cent anywhere in it and no cent is ever split.",
    "the_only_rounding_function": "Math.round on the double, which is half toward positive infinity: a value typed 0.005 is read as 1 hundredth and a value typed 0.004 as 0, and a count typed 2.5 is read as 3 and 2.4 as 2. The value reader and the count reader take the range test and the rounding in OPPOSITE orders, and that order is what decides what a negative figure does; both ranges start at 0. A VALUE has its range tested before it is rounded, so the negative half-cent is unreachable in a value rather than handled: a negative value of any size is out of range in the low direction, and a value typed -0.004 or -0.4 is read as not typed before any rounding of it can matter. A COUNT is rounded before its range is tested, as what_is_rounded and state.a_cell both say, so a negative cell figure of -0.5 or above rounds to zero, passes the range test and is read as a TYPED ZERO: a cell typed -0.4 or -0.5 is reported in cellsTyped and in cellsTypedZero and not in cellsNotTyped, and the chart prints it as the typed zero it was read as. A cell figure below -0.5 rounds to -1 or lower, fails the range test and is read as not typed. A typed zero adds nothing to either total, so no figure this engine reports can be negative at any of those states.",
    "the_two_margins": "Because every amount is a whole number of hundredths, the sum of the chore row totals and the sum of the person column totals are two integer sums of the same integers. Their difference is exactly 0 and is reported as 0.00, not as a figure inside a tolerance. An agent comparing its own arithmetic with this one should expect exactness in the counts and in the hundredths, and should not introduce a tolerance.",
    "why_it_is_said_here": "An agent re-doing this arithmetic rounds the typed value once and then works in hundredths. Rounding each product instead would give a different figure wherever a value finer than a hundredth was typed, and rounding at the end would give a different one again."
  },
  "formulas": {
    "a_cell": "cell(chore, person) = the count typed in that cell, or nothing where the cell is blank or out of range. A blank cell and a typed zero both contribute nothing; they are counted separately and reported as cellsTypedZero and cellsNotTyped.",
    "times_done_of_a_chore": "choreTimes<j> = the sum of the counts in row j's cells, over the live columns only.",
    "the_total_of_a_chore": "choreTotal<j> = choreTimes<j> multiplied by row j's value, in whole hundredths of row j's unit, where row j carries a value this engine read AND a unit this engine read. Where it carries neither, or only one of the two, the row has no total and the figure reported is 0 while the page prints the words saying no value is typed.",
    "times_done_of_a_person": "personTimes<i> = the sum, over the live rows, of the count in column i of each row.",
    "what_a_person_earned": "personMoney<i> = the sum, over the live rows whose unit is money and whose value was read, of the count in column i multiplied by that row's value. personPoints<i> is the same sum over the rows whose unit is points. Each is built up out of that person's own cells and out of nothing else: no total is divided, no share is taken and no weight is applied anywhere.",
    "the_grand_totals": "timesDoneTotal = the sum of choreTimes over the live rows. moneyTotal = the sum of choreTotal over the live rows whose unit is money. pointsTotal = the same over the rows whose unit is points. The two amount totals are two and never one: this engine does not add a figure in points to a figure in money under any circumstances.",
    "the_cross_foot": "crossFootMoneyDiff = moneyTotal less the sum of personMoney over the live columns. crossFootPointsDiff and crossFootCountDiff are the same difference in the other two units. All three are 0 in every state this engine can reach, which is the arithmetic claim the page makes: the two margins are added by different routes through the same cells and they agree.",
    "nothing_is_divided": "There is no division anywhere in this engine. No figure is divided by another, no total is shared out, no percentage and no ratio is computed, and there is therefore no guard against dividing by nothing because there is nothing to guard."
  },
  "completeness": {
    "an_entry_is_complete": "when at least one chore carries both a value and a unit this engine read, AND no chore carries a count anywhere without a value. Until both hold, the page withholds every amount it would print in the corner.",
    "what_that_withholds": "The two headline tiles, the corner of the chart, the six money and points lines of the two margins and the six money and points lines of the working. Each of those prints the words saying the amount is not shown, and the sentence saying which rows are holding it back prints in the glance above them. It withholds nothing else, and the figure is withheld in every one of those places on the same condition, so one quantity never has two answers.",
    "what_it_does_not_withhold": "The counts. Every times-done figure on the page prints in every state, because a count is complete on its own and because the chart has to be usable as a chart before anything is valued. It also does not withhold a chore row's OWN total, which is a different quantity and withholds on its own condition: whether that row carries a value in a unit this engine read. So a valued row prints its own total in a state where the corner does not.",
    "a_person_whose_amount_is_withheld": "A column whose cells include a count against a row with no value has that column's amount in that row's unit withheld too, because the amount that cell would have entered is not known. A column with no such cell prints its amount, which is a sum over the rows that were valued.",
    "waiting_is_not_an_error": "A chart with no value on it is a chart. A chore with a value and no count anywhere comes to zero and prints as zero. A labelled column that adds to nothing keeps its place and reads zero. None of the three is withheld and none of them is a fault."
  },
  "states": [
    {
      "state": "no value against any chore",
      "reached_when": "no live row carries both a value and a unit this engine read",
      "printed": "no amount in the corner, in the two margins or in the working; the counts print throughout; the glance says there is no value typed against any chore"
    },
    {
      "state": "a count typed against a chore with no value",
      "reached_when": "a live row's cells add to more than nothing and that row carries no value",
      "printed": "that row's count prints and its amount does not; the amount is withheld in that person's column in that row's unit and in the corner; the glance names the rows concerned"
    },
    {
      "state": "a chore with a value and no count anywhere",
      "reached_when": "a live row carries a value and a unit and every one of its cells is blank or a typed zero",
      "printed": "the row total is zero and prints as zero rather than vanishing; choresValuedNoCount counts it"
    },
    {
      "state": "a labelled column that adds to nothing",
      "reached_when": "every cell in a live column is blank or a typed zero",
      "printed": "the column keeps its place and reads zero in all three of its lines; columnsWithNoCell counts it"
    },
    {
      "state": "a typed zero beside a cell left empty",
      "reached_when": "one cell of a live row reads 0 and another reads nothing",
      "printed": "the chart shows 0 for the first and a dash for the second; cellsTypedZero and cellsNotTyped count them separately; both add nothing"
    },
    {
      "state": "money against one chore and points against another",
      "reached_when": "at least one live valued row is in money and at least one is in points",
      "printed": "two totals, never one; the page says that the two are kept apart and that it will not add them; mixedUnits is true"
    },
    {
      "state": "a chore carrying a value in no unit this engine read",
      "reached_when": "a live row's unit is neither money nor points, which the page's own control cannot produce",
      "printed": "that row's amount is in neither total, the row total says no value is typed, and the page says the reading came from a caller rather than from the chart; choresValuedNoUnit counts it"
    },
    {
      "state": "a count or a value typed outside the range the controls offer",
      "reached_when": "a cell reads above 99 or below 0, or a value reads above 999.99 or below 0",
      "printed": "the figure is read as not typed in either direction and never pulled to the nearest value the control offers"
    },
    {
      "state": "one column and one chore",
      "reached_when": "both counts read 1, which is the shape the page's input-block fallback line describes",
      "printed": "one cell, one total and no split at all, because a per-person or a per-chore figure is only what a count in each cell produces"
    },
    {
      "state": "the whole grid at its widest",
      "reached_when": "six columns, ten rows and a count in all sixty cells",
      "printed": "every figure above, with the two margins still agreeing exactly, because both are integer sums of the same hundredths"
    }
  ],
  "outputs": [
    { "name": "peopleLive", "type": "integer", "of": "how many columns this engine read, 1 to 6" },
    { "name": "choresLive", "type": "integer", "of": "how many rows this engine read, 1 to 10" },
    { "name": "waiting", "type": "boolean", "of": "whether the page is withholding the amounts it would print in the corner. True exactly when no live row carries both a value and a unit, or a live row carries a count with no value." },
    { "name": "anyPlaced", "type": "boolean", "of": "whether at least one live row carries both a value and a unit this engine read" },
    { "name": "mixedUnits", "type": "boolean", "of": "whether at least one live valued row is in money and at least one is in points, which is the state in which the page says it will not add the two" },
    { "name": "moneyRowsPresent", "type": "boolean", "of": "whether at least one live row carries a value in money" },
    { "name": "pointsRowsPresent", "type": "boolean", "of": "whether at least one live row carries a value in points" },
    { "name": "timesDoneTotal", "type": "integer", "of": "the sum of every cell of the grid, which is both margins' own count total" },
    { "name": "moneyTotal", "type": "number", "of": "the sum of the row totals of the live rows valued in money, to two decimal places" },
    { "name": "pointsTotal", "type": "number", "of": "the sum of the row totals of the live rows valued in points, to two decimal places" },
    { "name": "choresValued", "type": "integer", "of": "how many live rows carry a value this engine read" },
    { "name": "choresPlaced", "type": "integer", "of": "how many live rows carry a value AND a unit this engine read, which are the rows that have a row total" },
    { "name": "choresCountedNoValue", "type": "integer", "of": "how many live rows carry a count somewhere and no value, which is the second branch of the waiting rule" },
    { "name": "choresValuedNoCount", "type": "integer", "of": "how many live rows carry a value and a unit and add to nothing, whose row total is zero and prints as zero" },
    { "name": "choresValuedNoUnit", "type": "integer", "of": "how many live rows carry a value in no unit this engine read, which the page's own control cannot produce" },
    { "name": "columnsWithNoCell", "type": "integer", "of": "how many live columns add to nothing, which keep their place and read zero" },
    { "name": "cellsTyped", "type": "integer", "of": "how many cells of the live grid carry a figure this engine read, a typed zero included" },
    { "name": "cellsTypedZero", "type": "integer", "of": "how many cells of the live grid carry a typed zero, which is kept apart from a cell left empty" },
    { "name": "cellsNotTyped", "type": "integer", "of": "how many cells of the live grid carry nothing this engine could read" },
    { "name": "crossFootMoneyDiff", "type": "number", "of": "the money total less the sum of what the columns earned in money. 0.00 in every reachable state." },
    { "name": "crossFootPointsDiff", "type": "number", "of": "the points total less the sum of what the columns earned in points. 0.00 in every reachable state." },
    { "name": "crossFootCountDiff", "type": "integer", "of": "the rows' count total less the columns' count total. 0 in every reachable state." },
    { "name": "choreTimes1", "type": "integer", "of": "the times done in row 1, across the live columns. 0 where row 1 is not live." },
    { "name": "choreTimes2", "type": "integer", "of": "the times done in row 2. 0 where row 2 is not live." },
    { "name": "choreTimes3", "type": "integer", "of": "the times done in row 3. 0 where row 3 is not live." },
    { "name": "choreTimes4", "type": "integer", "of": "the times done in row 4. 0 where row 4 is not live." },
    { "name": "choreTimes5", "type": "integer", "of": "the times done in row 5. 0 where row 5 is not live." },
    { "name": "choreTimes6", "type": "integer", "of": "the times done in row 6. 0 where row 6 is not live." },
    { "name": "choreTimes7", "type": "integer", "of": "the times done in row 7. 0 where row 7 is not live." },
    { "name": "choreTimes8", "type": "integer", "of": "the times done in row 8. 0 where row 8 is not live." },
    { "name": "choreTimes9", "type": "integer", "of": "the times done in row 9. 0 where row 9 is not live." },
    { "name": "choreTimes10", "type": "integer", "of": "the times done in row 10. 0 where row 10 is not live." },
    { "name": "choreTotal1", "type": "number", "of": "row 1's own total, in row 1's own unit, to two decimal places. 0 where the row is not live or carries no value this engine could place." },
    { "name": "choreTotal2", "type": "number", "of": "row 2's own total, read as choreTotal1." },
    { "name": "choreTotal3", "type": "number", "of": "row 3's own total, read as choreTotal1." },
    { "name": "choreTotal4", "type": "number", "of": "row 4's own total, read as choreTotal1." },
    { "name": "choreTotal5", "type": "number", "of": "row 5's own total, read as choreTotal1." },
    { "name": "choreTotal6", "type": "number", "of": "row 6's own total, read as choreTotal1." },
    { "name": "choreTotal7", "type": "number", "of": "row 7's own total, read as choreTotal1." },
    { "name": "choreTotal8", "type": "number", "of": "row 8's own total, read as choreTotal1." },
    { "name": "choreTotal9", "type": "number", "of": "row 9's own total, read as choreTotal1." },
    { "name": "choreTotal10", "type": "number", "of": "row 10's own total, read as choreTotal1." },
    { "name": "personTimes1", "type": "integer", "of": "the times done in column 1, across the live rows. 0 where column 1 is not live." },
    { "name": "personTimes2", "type": "integer", "of": "the times done in column 2. 0 where column 2 is not live." },
    { "name": "personTimes3", "type": "integer", "of": "the times done in column 3. 0 where column 3 is not live." },
    { "name": "personTimes4", "type": "integer", "of": "the times done in column 4. 0 where column 4 is not live." },
    { "name": "personTimes5", "type": "integer", "of": "the times done in column 5. 0 where column 5 is not live." },
    { "name": "personTimes6", "type": "integer", "of": "the times done in column 6. 0 where column 6 is not live." },
    { "name": "personMoney1", "type": "number", "of": "what column 1 earned in money, built up out of that column's own cells at the values of the rows they sit on, to two decimal places" },
    { "name": "personMoney2", "type": "number", "of": "what column 2 earned in money, read as personMoney1." },
    { "name": "personMoney3", "type": "number", "of": "what column 3 earned in money, read as personMoney1." },
    { "name": "personMoney4", "type": "number", "of": "what column 4 earned in money, read as personMoney1." },
    { "name": "personMoney5", "type": "number", "of": "what column 5 earned in money, read as personMoney1." },
    { "name": "personMoney6", "type": "number", "of": "what column 6 earned in money, read as personMoney1." },
    { "name": "personPoints1", "type": "number", "of": "what column 1 earned in points, built the same way over the rows valued in points, to two decimal places" },
    { "name": "personPoints2", "type": "number", "of": "what column 2 earned in points, read as personPoints1." },
    { "name": "personPoints3", "type": "number", "of": "what column 3 earned in points, read as personPoints1." },
    { "name": "personPoints4", "type": "number", "of": "what column 4 earned in points, read as personPoints1." },
    { "name": "personPoints5", "type": "number", "of": "what column 5 earned in points, read as personPoints1." },
    { "name": "personPoints6", "type": "number", "of": "what column 6 earned in points, read as personPoints1." }
  ],
  "worked_example": {
    "why": "one chart worked end to end: two columns, three rows, money against two rows and points against the third, a typed zero in one cell, a blank cell beside it, and one row carrying a value and no count anywhere. Every figure below is this engine's own answer for the state above it.",
    "state": {
      "peopleCount": "2",
      "people": [{ "label": "A" }, { "label": "J" }],
      "choreCount": 3,
      "chores": [
        { "name": "row one", "value": "2.50", "unit": "money", "count1": "4", "count2": "2" },
        { "name": "row two", "value": "6.00", "unit": "points", "count1": "1", "count2": "3" },
        { "name": "row three", "value": "1.25", "unit": "money", "count1": "0", "count2": "" }
      ]
    },
    "outputs": {
      "peopleLive": 2, "choresLive": 3, "waiting": false, "anyPlaced": true, "mixedUnits": true,
      "moneyRowsPresent": true, "pointsRowsPresent": true,
      "timesDoneTotal": 10, "moneyTotal": 15, "pointsTotal": 24,
      "choresValued": 3, "choresPlaced": 3, "choresCountedNoValue": 0, "choresValuedNoCount": 1,
      "choresValuedNoUnit": 0, "columnsWithNoCell": 0,
      "cellsTyped": 5, "cellsTypedZero": 1, "cellsNotTyped": 1,
      "crossFootMoneyDiff": 0, "crossFootPointsDiff": 0, "crossFootCountDiff": 0,
      "choreTimes1": 6, "choreTimes2": 4, "choreTimes3": 0, "choreTimes4": 0, "choreTimes5": 0,
      "choreTimes6": 0, "choreTimes7": 0, "choreTimes8": 0, "choreTimes9": 0, "choreTimes10": 0,
      "choreTotal1": 15, "choreTotal2": 24, "choreTotal3": 0, "choreTotal4": 0, "choreTotal5": 0,
      "choreTotal6": 0, "choreTotal7": 0, "choreTotal8": 0, "choreTotal9": 0, "choreTotal10": 0,
      "personTimes1": 5, "personTimes2": 5, "personTimes3": 0, "personTimes4": 0, "personTimes5": 0, "personTimes6": 0,
      "personMoney1": 10, "personMoney2": 5, "personMoney3": 0, "personMoney4": 0, "personMoney5": 0, "personMoney6": 0,
      "personPoints1": 6, "personPoints2": 18, "personPoints3": 0, "personPoints4": 0, "personPoints5": 0, "personPoints6": 0
    },
    "read_it_back": "Row one was done six times, four of them by the first column and two by the second, at 2.50 each: 15.00 in money. Row two was done four times at 6.00 each: 24.00 in points. Row three carries a value, a typed zero in the first column and nothing in the second, so it was done no times at all and comes to 0.00 rather than disappearing. Added down the rows the money reaches 15.00 and the points reach 24.00; added across the columns the money reaches 10.00 and 5.00, which is 15.00, and the points reach 6.00 and 18.00, which is 24.00. Both differences are 0.00 and the count difference is 0. The money and the points are two totals and are never added into one."
  },
  "second_worked_example": {
    "why": "the narrow shape the page's input-block fallback line describes: one column, one chore, one cell holding the whole week at the top of its range. It is here because it is the only shape in which a remembered total can be typed at all, and because it shows what that costs - one figure and no split of any kind.",
    "state": {
      "peopleCount": "1",
      "people": [{ "label": "A" }],
      "choreCount": "1",
      "chores": [{ "name": "row one", "value": "0.75", "unit": "money", "count1": "99" }]
    },
    "outputs": {
      "peopleLive": 1, "choresLive": 1, "waiting": false, "anyPlaced": true, "mixedUnits": false,
      "moneyRowsPresent": true, "pointsRowsPresent": false,
      "timesDoneTotal": 99, "moneyTotal": 74.25, "pointsTotal": 0,
      "choresValued": 1, "choresPlaced": 1, "choresCountedNoValue": 0, "choresValuedNoCount": 0,
      "choresValuedNoUnit": 0, "columnsWithNoCell": 0,
      "cellsTyped": 1, "cellsTypedZero": 0, "cellsNotTyped": 0,
      "crossFootMoneyDiff": 0, "crossFootPointsDiff": 0, "crossFootCountDiff": 0,
      "choreTimes1": 99, "choreTimes2": 0, "choreTimes3": 0, "choreTimes4": 0, "choreTimes5": 0,
      "choreTimes6": 0, "choreTimes7": 0, "choreTimes8": 0, "choreTimes9": 0, "choreTimes10": 0,
      "choreTotal1": 74.25, "choreTotal2": 0, "choreTotal3": 0, "choreTotal4": 0, "choreTotal5": 0,
      "choreTotal6": 0, "choreTotal7": 0, "choreTotal8": 0, "choreTotal9": 0, "choreTotal10": 0,
      "personTimes1": 99, "personTimes2": 0, "personTimes3": 0, "personTimes4": 0, "personTimes5": 0, "personTimes6": 0,
      "personMoney1": 74.25, "personMoney2": 0, "personMoney3": 0, "personMoney4": 0, "personMoney5": 0, "personMoney6": 0,
      "personPoints1": 0, "personPoints2": 0, "personPoints3": 0, "personPoints4": 0, "personPoints5": 0, "personPoints6": 0
    },
    "read_it_back": "Ninety-nine at 0.75 is 74.25, and that is the whole answer: one row, one column, one cell. The row total and the column total are the same figure because there is only one cell for either margin to add, which is exactly why a remembered total yields no per-person and no per-chore figure. The points total is 0.00 because nothing was typed in points, not because anything was withheld."
  },
  "third_worked_example": {
    "why": "the second spelling, which is the one the workbook sold beside this page is read against: people as plain labels and each chore carrying a counts array, with a typed zero, two blank cells and both units in play. Nothing about the answer differs from the first spelling.",
    "state": {
      "people": ["A", "J", "Sam"],
      "chores": [
        { "name": "row one", "value": "1.25", "unit": "money", "counts": [0, null, 3] },
        { "name": "row two", "value": "10.00", "unit": "points", "counts": [2, 2, null] }
      ]
    },
    "outputs": {
      "peopleLive": 3, "choresLive": 2, "waiting": false, "anyPlaced": true, "mixedUnits": true,
      "moneyRowsPresent": true, "pointsRowsPresent": true,
      "timesDoneTotal": 7, "moneyTotal": 3.75, "pointsTotal": 40,
      "choresValued": 2, "choresPlaced": 2, "choresCountedNoValue": 0, "choresValuedNoCount": 0,
      "choresValuedNoUnit": 0, "columnsWithNoCell": 0,
      "cellsTyped": 4, "cellsTypedZero": 1, "cellsNotTyped": 2,
      "crossFootMoneyDiff": 0, "crossFootPointsDiff": 0, "crossFootCountDiff": 0,
      "choreTimes1": 3, "choreTimes2": 4, "choreTimes3": 0, "choreTimes4": 0, "choreTimes5": 0,
      "choreTimes6": 0, "choreTimes7": 0, "choreTimes8": 0, "choreTimes9": 0, "choreTimes10": 0,
      "choreTotal1": 3.75, "choreTotal2": 40, "choreTotal3": 0, "choreTotal4": 0, "choreTotal5": 0,
      "choreTotal6": 0, "choreTotal7": 0, "choreTotal8": 0, "choreTotal9": 0, "choreTotal10": 0,
      "personTimes1": 2, "personTimes2": 2, "personTimes3": 3, "personTimes4": 0, "personTimes5": 0, "personTimes6": 0,
      "personMoney1": 0, "personMoney2": 0, "personMoney3": 3.75, "personMoney4": 0, "personMoney5": 0, "personMoney6": 0,
      "personPoints1": 20, "personPoints2": 20, "personPoints3": 0, "personPoints4": 0, "personPoints5": 0, "personPoints6": 0
    },
    "read_it_back": "Neither count is supplied, so the two lists say how wide the chart is: three columns and two rows. Row one holds a typed zero, a blank and a 3, which is three times done at 1.25, so 3.75 in money, all of it the third column's. Row two holds 2, 2 and a blank, which is four times done at 10.00, so 40.00 in points, split 20.00 and 20.00 between the first two columns. Seven cells' worth of counting in all, with one typed zero and two blanks reported separately, and both margins agreeing exactly in both units."
  },
  "limits": [
    "No chore, chore list, chore-by-age table, difficulty rating, frequency or duration is supplied, and no chore is suggested for anybody. Every chore here is one the reader typed.",
    "No amount is supplied: no allowance, pocket money, pay rate, points scale, typical figure or average figure, and no claim about what any chore is worth or about what anybody else does.",
    "No parenting, discipline, reward, punishment, incentive, motivation, screen-time or consequence advice, and no claim about chores and responsibility, chores and character or chores and outcomes.",
    "No developmental, educational, psychological, behavioural, health or safety claim, and nothing about what anyone of any age can, should or should not do.",
    "No employment, wage, minimum-wage, tax, benefit or child-labour statement, and nothing here is pay in any legal sense.",
    "No verdict, grade, star, rank, league table or comparison between people, and no ordering by what anybody earned: the rows sit in the order typed and the columns in the order labelled.",
    "A figure in points is never added to a figure in money. There are two amount totals and there is no state in which there is one.",
    "Nothing is divided: no typed total is allocated, no share is computed, and no percentage and no ratio is reported anywhere.",
    "No name, age, date of birth, school, class, year group, photo or date of any kind is an input, and there is no field for one in the state. A column carries a label, up to 24 characters, and nothing else.",
    "A remembered total is not an input. There is no field for one, because one figure cannot say which cell each of its parts belonged to; the page's input block says what to do instead, which is to set the chart to one column and one chore and accept that there is then no split at all.",
    "It counts what is typed. A chore left off the chart, or a cell left empty when something was done, is in no figure here and nothing in this engine can know that it is missing."
  ]
}
