Fetching latest headlines…

Dev

Settings Precedence Stays Put Until Nine Rows Match

Dev.toUnited States · NORTH AMERICA

A messy settings loader should not move until nine rows match. Characterization tests freeze current outputs before any extraction. The smallest safe change is one read function with identical results...

1 views0 likes0 comments

A messy settings loader should not move until nine rows match. Characterization tests freeze current outputs before any extraction. The smallest safe change is one read function with identical results.

The conclusion in one gate

Nine frozen rows are the refactor gate for this loader. A green run allows one env read to move. A red run forces an immediate revert of that edit.

The messy shape

Many small repos grow one function that reads three sources. Defaults sit beside file JSON and environment keys. Precedence lives in branch order, not in a named rule.

That shape is common after fast generated edits. The code runs, so the team calls it done. A cleanup then swaps branch order and ships a silent change.

This note does not claim a field study or a user count. The nine rows below are a designed fixture, not a production sample. Treat every command as an unexecuted proposal until you run it.

Source order to freeze

The legacy order in this example is fixed. Defaults load first for timeout, region, and debug. File JSON overwrites a key when that key exists.

Environment values overwrite next when the value is non-empty. An empty environment string does not overwrite a file value. Python str on a JSON boolean stays in the frozen output.

Those six rules are the behavior to protect. They are not a recommendation for new services. A later product change can replace them in a separate commit.

Step 1. Copy the loader unchanged

Place the legacy function in a test file before any rename. Keep file reads outside the function so tests pass text. Return a plain dictionary and avoid printing secrets.

import json

def load_settings(env, file_text):
    data = {"timeout": "30", "region": "us", "debug": "0"}
    if file_text:
        parsed = json.loads(file_text)
        for key in ("timeout", "region", "debug"):
            if key in parsed:
                data[key] = str(parsed[key])
    for key in ("timeout", "region", "debug"):
        env_key = key.upper()
        if env_key in env and env[env_key] != "":
            data[key] = env[env_key]
    return data

This block is the characterization target for the gate. It is labeled legacy on purpose in this file. Do not tidy branches while you copy it.

Step 2. Write nine rows by id

Store inputs and expected dictionaries in one list. Do not recompute the expected map inside the assertion. A failure message should print the row id only.

ROWS = [
    {
        "id": "e1",
        "env": {"TIMEOUT": "15"},
        "file": "",
        "out": {"timeout": "15", "region": "us", "debug": "0"},
    },
    {
        "id": "e2",
        "env": {"REGION": "eu"},
        "file": "",
        "out": {"timeout": "30", "region": "eu", "debug": "0"},
    },
    {
        "id": "e3",
        "env": {"DEBUG": "1"},
        "file": "",
        "out": {"timeout": "30", "region": "us", "debug": "1"},
    },
    {
        "id": "f1",
        "env": {},
        "file": '{"timeout": 9}',
        "out": {"timeout": "9", "region": "us", "debug": "0"},
    },
    {
        "id": "f2",
        "env": {},
        "file": '{"region": "ap"}',
        "out": {"timeout": "30", "region": "ap", "debug": "0"},
    },
    {
        "id": "f3",
        "env": {},
        "file": '{"debug": true}',
        "out": {"timeout": "30", "region": "us", "debug": "True"},
    },
    {
        "id": "m1",
        "env": {"TIMEOUT": "15"},
        "file": '{"timeout": 9, "region": "ap"}',
        "out": {"timeout": "15", "region": "ap", "debug": "0"},
    },
    {
        "id": "m2",
        "env": {"TIMEOUT": ""},
        "file": '{"timeout": 9}',
        "out": {"timeout": "9", "region": "us", "debug": "0"},
    },
    {
        "id": "m3",
        "env": {"DEBUG": "0"},
        "file": '{"debug": true}',
        "out": {"timeout": "30", "region": "us", "debug": "0"},
    },
]

Row f3 freezes the string True from a JSON boolean. Row m2 freezes the empty-string skip on timeout. Row m3 freezes an environment win over that boolean cast.

Step 3. Assert identity, then count passes

Use the standard library runner so the gate stays small. Compare full dictionaries, not single fields, in each check. Stop on the first bad id if you want a short log.

Keep the loader, the rows, and the test class in one file. Name that file test_settings_rows.py so the command below matches.

import unittest

class SettingsRowsTest(unittest.TestCase):
    def test_nine_rows_match(self):
        for row in ROWS:
            got = load_settings(row["env"], row["file"])
            self.assertEqual(got, row["out"], row["id"])

if __name__ == "__main__":
    unittest.main()
python test_settings_rows.py -v
python -m unittest test_settings_rows.SettingsRowsTest.test_nine_rows_match

Expect one test method and nine equality checks. Record the command in the change note for reviewers. Do not record a pass you have not seen on your machine.

The json and unittest modules are documented in the Python standard library. Use those pages to confirm parsing and runner behavior before you publish. See the json docs and the unittest docs.

Step 4. Move only the env read

Extract read_env_value and leave file parsing in place. Keep the empty-string check inside that new helper. Call it once per known key and assign only on a hit.

def read_env_value(env, key):
    env_key = key.upper()
    if env_key in env and env[env_key] != "":
        return env[env_key]
    return None

def load_settings(env, file_text):
    data = {"timeout": "30", "region": "us", "debug": "0"}
    if file_text:
        parsed = json.loads(file_text)
        for key in ("timeout", "region", "debug"):
            if key in parsed:
                data[key] = str(parsed[key])
    for key in ("timeout", "region", "debug"):
        value = read_env_value(env, key)
        if value is not None:
            data[key] = value
    return data

Re-run the same unittest command after this edit. All nine ids must still match the frozen maps. If one id fails, revert the helper before a second idea.

Step 5. Reject three common drifts

Drift one lowercases JSON booleans during the move. Row f3 would change from True to true. That is a behavior edit, so it needs a new row set.

Drift two treats an empty environment string as an override. Row m2 would change timeout from 9 to empty. Keep the empty check until a product decision says otherwise.

Drift three reads unknown environment keys into the map. The nine rows never asked for that expansion. Add a tenth row before you widen the key list.

A free model pass and a free server run

Disclosure: This article was prepared as part of MonkeyCode's product outreach. MonkeyCode free model access can draft the nine-row list from the legacy function. A reviewer still checks each expected dictionary by hand.

Generated rows are a starting table, not an approval. MonkeyCode free server option can run the unittest command in a clean workspace. Use fixture text only, and do not paste live secrets into the prompt.

No model name, quota, hardware shape, or time limit is stated here. Those details were not supplied for this note. Confirm current free access terms in the product console first.

Decision table for the next edit

Use this table before you open a second commit. Read each signal as a review rule, not a score.

Signal Next action
Nine ids match after the helper move Stop, and commit that one move
Any id mismatches Revert the helper, then reread the branch
A new key is requested Add a row, then rerun the nine plus one
Boolean coercion is requested New expected maps, separate from this refactor
Invalid JSON handling is requested Add a throwing-row test in a later pass
Live environment samples appear Remove them, and keep synthetic values only

The table is a review aid for this loader. It is not a measured incident log from production. Your repo may need more rows than these nine.

Limits of the nine-row gate

The gate misses unknown keys and nested JSON objects. It misses invalid JSON, comments, and duplicate keys. It also misses concurrent writers and file permission errors.

A matching run does not prove precedence for keys outside the tuple. Timeout, region, and debug are the only watched names. Add rows when the watched set grows past three names.

Free model drafts can copy a wrong branch and still look tidy. Free server runs can pass while local path code differs. Compare the tested file hash with the file you plan to merge.

Print a sha256 of the tested file with the standard library. Store that digest beside the unittest command in the change note.

python -c "import hashlib, pathlib; p = pathlib.Path('test_settings_rows.py'); print(hashlib.sha256(p.read_bytes()).hexdigest())"

Who should skip this approach

Skip this gate when no one can name the current output. Guessed expected maps freeze a fiction, not the code. Write a short discovery note instead of a false green.

Skip it when the business must change precedence in this same release. That work is a behavior change, not a move. Put the new rule in new rows, and retire the old rows on purpose.

Skip it when tests cannot run in the target environment. A helper extraction without a rerun is an unchecked edit. Wait until the nine checks can execute on that environment.

Skip it when the loader reads secrets into logs during tests. Characterization should not create a new leak path. Strip secret-shaped values before any model prompt or server job.

Review checklist before merge

Confirm the diff touches the env read and not the file loop. Confirm row f3 still expects the string True. Confirm row m2 still expects timeout 9 from the file.

Confirm the change note names the unittest command. Confirm no live credential appears in the ROWS list. Confirm a human compared helper output with the frozen maps.

What this note refuses to claim

This note does not rank coding tools or publish a score. It does not report a runtime, cost, or lab pass rate. It does not say the free options will remain available on any date.

The durable artifact is the nine-row table plus one helper boundary. Keep that artifact in the repo even if the tool choice changes.

Close the gate

If your loader has the same three-source knot, freeze nine rows first. Let a reviewer own the expected maps before any helper move. Rerun the same command after that single move, and stop there.

Comments (0)

Sign in to join the discussion

Be the first to comment!