Skip to content
CogniSkill

LESSON 4 OF 4

Prove the rule and complete an independent project

Practice notesBooks for further learning

Execute tests that can disagree with the implementation

Save the following as test_reconcile_inventory.py beside the program. The expected directional and field-mismatch outputs are literal fixture conclusions. They are not calculated by copying the comparison loop into a test helper.

import tempfile
import unittest
from pathlib import Path
import reconcile_inventory as target

class ReconciliationTests(unittest.TestCase):
    def test_normalization(self):
        got = target.normalize_row({'asset_id':' a-001 ', 'owner_id':'u101', 'site':'hq'},2)
        self.assertEqual(got, {'asset_id':'A-001', 'owner_id':'u101', 'site':'HQ'})

    def test_two_field_mismatch_is_two_rows_one_asset(self):
        reg = {'A-002': {'asset_id':'A-002', 'owner_id':'u102', 'site':'HQ'}}
        obs = {'A-002': {'asset_id':'A-002', 'owner_id':'u999', 'site':'BRANCH'}}
        self.assertEqual(target.compare(reg, obs), [
            {'asset_id':'A-002','finding':'FIELD_MISMATCH','field':'owner_id','registered':'u102','observed':'u999'},
            {'asset_id':'A-002','finding':'FIELD_MISMATCH','field':'site','registered':'HQ','observed':'BRANCH'},
        ])

    def test_direction_and_stable_order(self):
        same = {'asset_id':'A-001','owner_id':'u101','site':'HQ'}
        reg = {'A-004':{}, 'A-001':same}
        obs = {'A-005':{}, 'A-001':same}
        self.assertEqual(target.compare(reg, obs), [
            {'asset_id':'A-004','finding':'REGISTER_ONLY','field':'','registered':'present','observed':'absent'},
            {'asset_id':'A-005','finding':'OBSERVED_ONLY','field':'','registered':'absent','observed':'present'},
        ])

    def test_case_sensitive_owner_contract(self):
        with self.assertRaises(ValueError):
            target.normalize_row({'asset_id':'A-001','owner_id':'U101','site':'HQ'},2)

    def test_naive_capture_rejected(self):
        with self.assertRaises(ValueError):
            target.parse_capture('2026-10-01T09:00:00')

    def test_duplicate_after_normalization_rejected(self):
        with tempfile.TemporaryDirectory() as tmp:
            p = Path(tmp)
            (p/'input.csv').write_text('asset_id,owner_id,site\nA-001,u101,HQ\na-001,u101,HQ\n')
            (p/'manifest.json').write_text('{"complete":true,"row_count":2,"collected_at":"2026-10-01T09:00:00Z"}')
            with self.assertRaisesRegex(ValueError,'duplicate'):
                target.read_inventory(p/'input.csv',p/'manifest.json')

if __name__ == '__main__':
    unittest.main()

Run python -m unittest -v. All six tests should pass. The file tests create and remove only their own temporary directory. They do not delete the report you created in Chapter 3.

Introduce a deliberate defect in a separate program copy: when comparing sites, replace the observed site value with the registered site value. The two-field mismatch test must fail because the A-002 site mismatch disappears. Restore the original code and rerun. A test that passes the correct program but fails the defective one has demonstrated useful sensitivity.

The tests also distinguish direction, normalization and duplicate identity. They do not test every output-write failure or guarantee performance on millions of rows. Maintain a separate integration test table for file contracts and output preservation. Unit and integration tests answer different questions.

Project A — Add an anomalous population-change review gate

Design a configurable gate that flags an observed population decrease beyond an agreed percentage from a prior successful observed snapshot. It should mark the comparison for review, preserve the current evidence and prevent automated downstream lifecycle actions. It must not invent a missing device's status or modify the source files.

Define the denominator. If a previous observed snapshot had 100 assets and this one has 80, the population decrease is 20% of the previous count. If the previous count is zero, the ordinary percentage is undefined; state a separate policy. Decide whether a threshold of 20% triggers at exactly 20 or only above it, and test that boundary explicitly.

Use independent expected cases: previous 100/current 81, previous 100/current 80, previous 100/current 79, and previous 0/current 4. Include a valid growth case and an incomplete current export. Completeness rejection should occur before the population comparison gate, so an incomplete file cannot be reclassified as an ordinary inventory change.

Worked policy example

A review-at-or-above-20% policy does not flag 100→81, flags 100→80 and 100→79, and uses a separate “no baseline” state for 0→4. An incomplete current export is rejected rather than scored. This policy flags a source population anomaly; it does not establish that individual devices need deletion.

Project B — Accept reordered columns without hiding schema damage

The first version requires one exact header order. Extend it to accept the same three unique names in any order while still rejecting extra, missing and duplicate names. Preserve the output schema and ordering so downstream reports do not change unnecessarily.

A set comparison alone is insufficient: the header asset_id,owner_id,site,site has the same set of names as a valid header but includes a duplicate. Test both header length and unique membership, and validate row shape under the accepted header. Add literal expected cases for a reordered header, an extra header, a duplicate header and a renamed header.

Explain why this is a contract extension rather than a correction of the original report. The original strict order was intentional. Relaxing it can improve interoperability, but it should be a documented, tested versioned behavior change.

Project C — Draft a collector handoff contract

Design the collection stage that supplies these files. You do not need a live tenant to complete the design. Define the expected source population, read identity, permission scope, page-completion rule, timeout behavior, collection timestamp and manifest generation procedure. If collection fails after several pages, specify that the export is incomplete and cannot feed authoritative absence findings.

Record which upstream identifier is stable, whether it is case-sensitive and what duplicate observations mean. If the provider cannot guarantee a snapshot across pages, explain that records may change during collection. A completed page traversal and a transactionally consistent snapshot are different properties.

Connect this project to the REST API course: its page collector can demonstrate bounded pagination and failure handling using offline responses. It will still need an authorized provider adapter and verification before its output is a trustworthy fleet source. Do not remove that boundary merely because the fictional client returns tidy JSON.

Submit an evidence package

Your project folder should include the untouched baseline inputs, both manifests, the program, tests, a successful findings file, its summary and a failure-results table. Add a README with the identity normalization policy, accepted schema, population meaning, output publication limit and chosen extension.

A reviewer should be able to reproduce the baseline and answer these questions from your evidence: why there are four findings but three affected identities; why a duplicate key stops the batch; why changing source formatting changes a hash but may not change findings; why missing files are not empty inventories; and why the report cannot authorize device retirement.

For the extension, provide at least one positive case, one boundary case, one negative case and a defect demonstration. Explain the remaining limitation that matters most for real use. An honest limitation helps the next engineer decide what to verify; it is part of the deliverable rather than a footnote to conceal.

Final reasoning check

A collector declares complete with four rows, but you discover it was scoped to one of three business units. Can the report prove that register-only assets from the other units are absent? No. The program has validated the supplied file contract, not the collector's organization-wide authority.

Two identical normalized rows appear for the same asset. Is silently deduplicating them safe? Not under this course's declared unique-row contract. It would hide an upstream violation. An alternative policy needs explicit justification and tests.

The second report's generation time changes while its findings stay identical. Has deterministic comparison failed? No. Run metadata and comparison results have different contracts. Compare the fields whose stability you promised.

You finish this course by defending the comparison's evidence boundary and demonstrating a tested extension. The website completion check records learning progress; it does not certify a live integration or grant authority to modify an inventory.

References: Python's official CSV, pathlib, argparse and datetime documentation at https://docs.python.org/3/library/ . The runnable code is original course material, not a production collector.

Transfer project — changed conditions

Implement the fixture in a new practice directory. Test repeated identical input, reordered input, conflicting duplicates, malformed records and an injected write failure. Record the old output hash before each failing run and show it remains unchanged. Define exit status and summary counts so a scheduler can distinguish success, validation failure and operational failure. Do not test against production files.

Practical assessment rubric

Score each dimension 0–2: 0 = absent or materially incorrect; 1 = partly correct with an unresolved gap; 2 = correct, explicit and supported by the supplied evidence or an actual labeled lab result.

  1. Evidence/model: identify the relevant entities, inputs, assumptions and boundaries without inventing facts.
  2. Main result: derive the case-specific expected result, calculation or decision and show the intermediate reasoning.
  3. Failure/boundary: test the changed condition and explain why the original conclusion does or does not transfer.
  4. Verification: supply reproducible steps and expected/observed results; label manual traces as manual, not executed.
  5. Communication/safety: explain limitations, owners and a proportionate next action without unsafe or unnecessary access.

Target: at least 8/10, with no zero in main result or communication/safety. This is a local learning rubric, not an accredited certification standard. A written/manual solution demonstrates reasoning only; operational competence additionally requires the relevant executable lab in an authorized environment. The native multiple-choice score is separate and does not automatically grade this rubric.

Submission template

  • My input/evidence and assumptions:
  • Expected result with calculations or trace:
  • My implementation/decision and justification:
  • Changed-condition result:
  • Observed execution, or explicitly labeled manual trace:
  • Failure and recovery evidence:
  • Unverified limitation and next action:
  • Self-score with evidence for each dimension:

Remediation

If the main result is wrong, reconstruct the supplied case from the raw inputs before changing code or controls. If the boundary case is wrong, identify the assumption that changed and rerun both the original and changed case. If verification is missing, do not convert a prediction into an observed result. Reattempt the transfer task without copying the worked solution, then explain it to another person.

Official reference for further study

Assessment: explain your decisions

Choose an answer and write your reason before opening each explanation. Then explain why the other choices do not fit the evidence. Use missed questions to revisit the lesson. This knowledge check is only one part of assessment: complete the practical transfer project as well. It does not predict certification-exam success.

1. Why use DictReader?

  1. It respects CSV parsing and headers
  2. It grants permissions
  3. It automatically validates every number
Answer and explanation

It respects CSV parsing and headers — Parsing and validation are separate responsibilities.

2. What should an empty measurement become?

  1. A verified zero
  2. A validation error
  3. A successful normal device
Answer and explanation

A validation error — Missing evidence is not a zero measurement.

3. What belongs in a repeatable automation design?

  1. Unbounded append
  2. No errors
  3. Explicit output and rerun behavior
Answer and explanation

Explicit output and rerun behavior — Repeated runs must be predictable.

4. A-002 differs in owner and site, while A-004 and A-005 each occur in only one source. What is the result grain?

  1. Four finding rows concerning three asset identities.
  2. Four affected assets because there are four findings.
  3. Two findings because field changes should always be merged.
Answer and explanation

Four finding rows concerning three asset identities. — There are two field rows for A-002 and one presence row for each of A-004 and A-005. Counts must name their grain. The summary separates field rows, mismatching shared assets and directional population differences.

5. The observed collector declares complete:false. Should the program report register-only assets?

  1. Yes, because a readable CSV is enough.
  2. No; reject the incomplete export before issuing absence findings.
  3. Yes, if the number of rows is non-zero.
Answer and explanation

No; reject the incomplete export before issuing absence findings. — Missing records in a partial export cannot establish source absence. Even a complete declaration and matching count do not prove organization-wide authority; the collector scope still requires verification.

6. A-001 and a-001 both appear under the fixture case-insensitive identity contract. What must happen?

  1. The later row wins because dictionary assignment is convenient.
  2. Both count as separate assets.
  3. Reject the duplicate normalized identity instead of guessing a current row.
Answer and explanation

Reject the duplicate normalized identity instead of guessing a current row. — Normalization reveals that both rows refer to one identity. The unique-row contract requires rejection. Choosing a latest row needs revision/timestamp evidence and a separately defined policy.

7. Can the supplied batch be published under its contract?

  1. No; asset-2 has conflicting types.
  2. Yes; keep the last row silently.
  3. Yes; discard all duplicates without explanation.
Answer and explanation

No; asset-2 has conflicting types. — The contract permits identical duplicates but explicitly rejects conflicting values. Input order must not decide an undocumented business rule.

8. What should happen to the old report on validation failure?

  1. It is replaced with an empty success report.
  2. It remains intact.
  3. It is truncated immediately.
Answer and explanation

It remains intact. — The publication boundary must follow successful validation. Preserving the last valid output prevents a failed run from destroying usable data.

9. What best demonstrates repeatability here?

  1. The script prints “done.”
  2. Every exception is suppressed.
  3. Reruns and reordered input produce the same validated result under the documented rules.
Answer and explanation

Reruns and reordered input produce the same validated result under the documented rules. — A repeatability claim needs observable output and failure tests, not a success message.

Open the scored course assessment to use the existing practice-test engine. Earlier attempts remain part of your history.

YOUR NEXT STEP

Keep building your skills

No directly related CogniSkill book is mapped to this course yet. Continue with the free learning, or compare the publishing catalogue by your next goal.

Explore books by topic and goal →

Sign in to save lesson completion. Reading position is separate from completion.

Practice notes — your working space

Save predictions, outputs and explanations as you work. Notes stay on this browser, not your account; people sharing this browser can access them. Avoid passwords and sensitive data. Export to keep a portable copy, or clear your notes before leaving a shared device.

How was this lesson?

Help us improve this lesson.