schmonz.com is a Fediverse instance that uses the ActivityPub protocol. In other words, users at this host can communicate with people that use software like Mastodon, Pleroma, Friendica, etc. all around the world.

This server runs the snac software and there is no automatic sign-up process.

Search results for tag #refactoring

#refactoring boosted

[?]Dev Community » 🤖 🌐
@devto@www.urbanmind.net

When an AI agent breaks a monolithic PR into three smaller ones, the cross-cutting invariant that spans all three is exactly the thing that stops being reviewed. What to do instead.
The agent split the giant PR into three smaller PRs — and the bug that lived between them stayed invisible

    #refactoring boosted

    [?]Michael K. Laweh (Klytron) » 🌐
    @klytron@mastodon.social

    Stop letting bloated plugins slow down your application. Here is why you need a quarterly dependency audit. Read more at klytron.com.

      #refactoring boosted

      [?]Marine Tachibana » 🌐
      @citrus_marine@mas.to

      I somehow managed to execute the main scene, but the "refactoring" introduced tons of bugs.

      - Enemy doesn't move
      - Player slides left
      - Attacking forces Player to face left

      Enemy and Player share the same state logic, and I broke it.

      Alt...Shocasing the bugs described in the post

        #refactoring boosted

        [?]Nicolas Fränkel 🇪🇺🇺🇦🇬🇪 » 🌐
        @frankel@mastodon.top

        >Pipeline test slimmed from ~700 to ~220 lines

        While improving the line and the mutation . That's what I like to read at the end of a session.

        Refactoring production code is good, but don't forget tests! Tests are the unloved children of developers.

          #refactoring boosted

          [?]Dev Community » 🤖 🌐
          @devto@www.urbanmind.net

          The gate is simple: pin behavior on inputs you can see, then grade the refactor on inputs you cannot. A refactor that passes the visible corpus and fails the hidden one was never safe. It was fitted.

          Most characterization suites rot this way. You write tests against the three files you have open. The model, or you, then patches code until those three pass. Nothing proves the other forty inputs still behave.

          This post builds a fingerprint harness with a canary/holdout split. Then it sets a rule for the smallest change that can honestly ship.

          1. Define the behavior surface before you touch code


          A refactor preserves observable behavior. So you must name what is observable, or the word means nothing.

          For a CLI-shaped tool, four surfaces cover most of it:

          Surface

          Captured as

          Catches

          Exit code

          integer

          swallowed exceptions, new early returns

          stdout bytes

          SHA-256

          reordered fields, changed rounding, lost whitespace

          stderr presence

          boolean

          new warnings, debug prints left behind

          files written

          path + SHA-256 list

          changed output paths, dropped side files


          Deliberately excluded: internal call order, log timings, object identity. Those change under every refactor. Pinning them buys you failing tests and no safety.

          Write that list down first. Every later argument about "did we break it" resolves against this table, not against memory.

          2. Split the corpus before you look at results


          Take your input corpus. Sort the filenames. Give every third case to the holdout set. The rule is deterministic, so it is reproducible, and it is chosen before any code changes.

          corpus/
          case_000/input.txt
          case_001/input.txt
          ...

          Canary gets two-thirds. Holdout gets one-third. The holdout stays closed until the refactor is finished. Not after step three. After the last commit.

          Why one-third and not ten percent? Because one-third of thirty cases is ten, and ten is enough to see a pattern failure. One or two holdout cases can fail by coincidence and teach you nothing.

          If you have fewer than twelve cases, stop. Do not refactor. Collect inputs first.

          3. Record the baseline on the unmodified tree


          Run the harness on a clean checkout. Commit the JSON. This file is the contract.

          python3
          """fingerprint.py <repo> <corpus> <out.json> - pin observable behavior."""
          import hashlib, json, subprocess, sys, tempfile
          from pathlib import Path

          ROOT = Path(sys.argv[1]).resolve()
          CORPUS = Path(sys.argv[2]).resolve()
          OUT = Path(sys.argv[3]).resolve()
          TIMEOUT = 30

          def sha(data: bytes) -> str:
          return hashlib.sha256(data).hexdigest()

          def fingerprint(case: Path) -> dict:
          work = Path(tempfile.mkdtemp(prefix="fp-"))
          cmd = [sys.executable, str(ROOT / "tool.py"), str(case / "input.txt")]
          try:
          proc = subprocess.run(cmd, capture_output=True, cwd=work, timeout=TIMEOUT)
          except subprocess.TimeoutExpired:
          return {"timeout": True}
          files = sorted(
          [p.relative_to(work).as_posix(), sha(p.read_bytes())]
          for p in work.rglob("*")
          if p.is_file()
          )
          return {
          "exit": proc.returncode,
          "stdout": sha(proc.stdout),
          "stderr_present": bool(proc.stderr.strip()),
          "files": files,
          }

          def split(cases: list) -> dict:
          return {
          "canary": [c for i, c in enumerate(cases) if i % 3 != 0],
          "holdout": [c for i, c in enumerate(cases) if i % 3 == 0],
          }

          cases = sorted(p for p in CORPUS.iterdir() if (p / "input.txt").is_file())
          result = {name: {c.name: fingerprint(c) for c in group}
          for name, group in split(cases).items()}
          OUT.write_text(json.dumps(result, indent=2, sort_keys=True))
          print(f"canary={len(result['canary'])} holdout={len(result['holdout'])}")

          The script is short on purpose. It has no dependencies, no fixtures, and no framework. You can run it in CI or on a laptop.

          Run it twice on the untouched tree. If the two JSON files differ, you have nondeterminism. Fix that before any refactor, or every later failure is ambiguous.

          4. Set the smallest safe change rule


          The point of a gate is to constrain scope, not to bless ambition. Use the behavior surface table as a budget.

          Change touches

          Allowed in one commit

          Evidence required

          One function body, no signature

          yes

          canary + holdout match

          One function signature, internal callers only

          yes

          callers updated in same commit

          Module moved to a new path

          no

          separate commit, imports only

          Output ordering or formatting

          no

          explicit human sign-off

          Public function signature

          no

          not a refactor; it is a redesign


          Row five is the one people argue about. A signature change is a behavior change by definition. Ship it as its own reviewed change with its own tests, not folded into a cleanup.

          5. Replay, then read the two numbers separately


          After the change, run the harness again. Compare per split, never in aggregate.

          import json, sys

          base = json.load(open(sys.argv[1]))
          now = json.load(open(sys.argv[2]))

          exit_code = 0
          for name in ("canary", "holdout"):
          drifted = [k for k, v in base[name].items() if now[name].get(k) != v]
          print(f"{name}: {len(drifted)}/{len(base[name])} drifted")
          for k in drifted[:5]:
          print(f" - {k}")
          exit_code |= bool(drifted)

          sys.exit(exit_code)

          Three outcomes matter.

          1. Canary 0, holdout 0. The change is behavior-preserving on this corpus. Commit it.
          2. Canary 0, holdout > 0. The change is wrong. The corpus was broad; the tests were narrow. Revert the commit, do not patch the harness.
          3. Canary > 0. You already know what to do. Inspect the diff before touching a single assertion.

          Outcome two is the one that saves you. Without a holdout split, it looks exactly like outcome one.

          6. Apply the revert rule, not the negotiation rule


          When holdout drifts, the instinct is to update the expected values. Resist it once.

          Holdout drift cause

          Action

          Renamed output key

          revert; rename in a separate commit

          Changed float formatting

          revert; formatting is a behavior change

          Dropped file write

          revert; a side effect disappeared

          Genuine pre-existing bug

          revert, then fix bug separately, then re-baseline

          Corpus case is invalid input

          remove the case, re-baseline on clean tree


          Only the last row permits touching the baseline. And it requires re-running step three on an unmodified tree, so the contract stays honest.

          Where free model access fits, and where it does not


          The harness above is mechanical. The slow part is the corpus and the first draft of the fingerprint script — and that is where a free model tier is genuinely useful. I used MonkeyCode's free model access to draft the harness and to propose corpus edge cases, then read every line before running it. The operator also describes a free server option, which matters here for one reason: the replay must run on a clean machine, not your laptop with a stale virtualenv. A throwaway environment makes step three reproducible.

          Disclosure: This article was prepared as part of MonkeyCode's product outreach.

          Use the free tooling for the disposable parts. Do not let a model decide which behavior counts as observable. That table is a design decision, and it is yours.

          On availability: the operator states a free token allowance in the millions-per-account range, plus the free server option. Quotas and hardware change without notice. Verify current terms on the project page before you plan around them.

          Limitations and who should skip this


          • The fingerprint is byte-level. It will flag cosmetic changes you intended. That is the price of catching the ones you did not.
          • Thirty cases is a floor, not a target. Real tools need cases drawn from production traffic, not from your imagination.
          • Timing, memory, and concurrency are not covered. This gate says nothing about performance regressions.
          • Skip this if your tool has no stable text output. A UI-heavy service needs snapshot diffs of rendered state instead.
          • Skip this if the refactor changes the public contract. Then you want migration tests, not a preservation gate.


          The short version


          Pick four observable surfaces. Sort your corpus and hold out every third case. Baseline on a clean tree, twice. Change one thing. Replay both splits. If the holdout moves, revert.

          The hidden third is the only honest reviewer you get for free. If you try the harness, keep the corpus small and the rule strict at first — and tell me which holdout case caught you.

          Further reading: Martin Fowler on characterization tests, and Michael Feathers, "Working Effectively with Legacy Code", chapter 13.
          Hold Out a Third of Your Corpus: The Characterization Gate for a Messy Refactor

          #refactoring boosted

          [?]endri_lickollari » 🤖 🌐
          @oneofwhoom_@mastodon.social

          Moving a TypeScript file shouldn’t create 40 broken imports.

          npx --yes movesafe@0.1.0 mv src/foo.ts src/lib/foo.ts --dry-run
          debtdrone scan .

          Plan → rewrite aliases/barrels → verify → then measure the debt you just moved.

          What’s the worst monorepo move you’ve survived?
          endrilickollari.github.io/move

            #refactoring boosted

            [?]Dev Community » 🤖 🌐
            @devto@www.urbanmind.net

            Codemod the mechanical part of a rename with ast-grep, list the calls a pattern can't judge, and hand only those files to Claude Code or Codex.
            Let ast-grep Do the Rename. Hand Claude Code Only the Files It Couldn't

              #refactoring boosted

              [?]Dev Community » 🤖 🌐
              @devto@www.urbanmind.net

              Most refactors do not break because tests are missing. They break because the tests pin the wrong surface. Model-drafted tests make this worse, not better: they are fast, plausible, and confident about internals.

              My rule for messy repos is simple. Draft many candidate tests. Admit only three-gate survivors. Then make the smallest safe change.

              The three gates are determinism, assertion surface, and sentinel failure. A candidate test must pass all three before it can guard a refactor. A test that cannot fail is decoration.

              Below is the workflow I use, with a harness sketch you can run before trusting any thresholds.

              Step 0: Record one observed baseline


              Before writing a single test, capture what the code does today. Run the entrypoint once and store the raw output.

              python -m yourapp.report --account 42 > baseline/report.json
              sha256sum baseline/report.json

              That hash is your reference point for the whole session. If the refactor changes the bytes, you will know. Not "roughly the same JSON" — the same bytes, or an explained diff.

              Keep this file out of version control churn. You want diff noise to mean something.

              Step 1: Draft candidates with a free model


              This is where free model access helps most. Drafting candidate characterization tests is volume work, and volume is cheap. Judgment is not.

              Disclosure: This article was prepared as part of MonkeyCode's product outreach.

              Use a prompt contract, not a vague request. The contract below forces the model onto the observable surface and demands observed values.

              You are drafting characterization tests for an unchanged module.
              Rules:
              1. Import only the public API listed below. Never touch names starting with _.
              2. Each test performs one call and asserts one observable value or exact output string.
              3. Expected values must come from the observed run I pasted. Do not guess.
              4. No mocks of the module under test. Patch only network and clock.
              5. Name each test after the behavior, not the function: test_rounds_discount_to_cents.
              Public API: calculate_invoice, render_report
              Observed run: <paste baseline output>

              Ask for fifteen candidates, expect eight usable ones. Reject anything that asserts on a private attribute, a log line, or an exception message you did not paste.

              Run the gate script on the candidates before you read them closely. Reading first biases you toward keeping the clever ones.

              Step 2: Determinism gate


              A characterization test that flips on its own is worse than no test. It teaches the team to ignore red.

              Run every candidate twenty times with a different PYTHONHASHSEED. Require twenty passes.

              # tools/gate_candidate_tests.py (sketch, tighten thresholds for your repo)
              import os, subprocess, sys
              from pathlib import Path

              RUNS = 20

              def run_pytest(target: Path, seed: str) -> int:
              env = {**os.environ, "PYTHONHASHSEED": seed}
              cmd = [sys.executable, "-m", "pytest", "-q", "-p", "no:cacheprovider", str(target)]
              return subprocess.run(cmd, env=env, capture_output=True).returncode

              def determinism_gate(test_file: Path, runs: int = RUNS) -> bool:
              failures = [n for n in range(runs) if run_pytest(test_file, str(n)) != 0]
              print(f"determinism: {runs - len(failures)}/{runs} pass")
              return not failures

              Twenty runs is a floor, not a proof. It catches hash-order dependence, unseeded randomness, and real clock reads. It will not catch a branch that fires once a month.

              Use a free server for this step if your laptop sleeps. A gate that dies at run nine and reports "unknown" is a gate you will skip next time. Any always-on box works; the point is an uninterrupted twenty-run window.

              Step 3: Surface gate


              Now check what the assertions actually touch. Parse the test file and flag private attribute access.

              import ast

              def surface_violations(test_file: Path) -> list[str]:
              tree = ast.parse(test_file.read_text())
              bad =
              [] for node in ast.walk(tree):
              if isinstance(node, ast.Attribute) and node.attr.startswith("_"):
              bad.append(f"line {node.lineno}: private attribute .{node.attr}")
              return bad

              This is syntactic, so it misses indirect access through helpers. Treat a clean report as permission to look, not proof of safety.

              Two more manual checks matter. Does the test assert on a log message? Logs are not API. Does it assert on an exception type without a pinned message? That is fine for control flow, weak for refactors.

              Prefer assertions on returned data and rendered output. Those survive most internal moves.

              Step 4: Sentinel gate


              The most important check. A characterization test must fail when behavior changes.

              Write a sentinel patch: one deliberate, tiny behavior change. Apply it in a throwaway clone. The test must go red.

              --- a/pricing.py
              +++ b/pricing.py
              @@
              - return round(subtotal * (1 - rate), 2)
              + return round(subtotal * (1 - rate), 1)

              import shutil, tempfile

              def sentinel_gate(repo: Path, test_file: Path, sentinel: Path) -> bool:
              with tempfile.TemporaryDirectory() as tmp:
              work = Path(tmp) / "repo"
              shutil.copytree(repo, work, ignore=shutil.ignore_patterns(".git"))
              applied = subprocess.run(["git", "apply", "--unsafe-paths", str(sentinel)],
              cwd=work, capture_output=True)
              if applied.returncode != 0:
              print("sentinel patch did not apply; fix the sentinel first")
              return False
              red = run_pytest(work / test_file.relative_to(repo), "0") != 0
              print(f"sentinel: {'caught the change' if red else 'DECORATION'}")
              return red

              One sentinel per behavior you claim to protect. A test that stays green after a rounding change protects nothing about rounding.

              Step 5: Make the smallest safe change


              Only survivors guard the edit. Then the refactor rule applies: one edit, one full suite run.

              Green suite plus unchanged baseline hash means you moved code, not behavior. Red suite means you learned something cheap.

              Keep the change smaller than your confidence. If a test goes red, do not edit the test to match the new code. That is how refactors turn into silent behavior changes nobody reviews.

              Decision table

              Gate result

              Action

              Determinism fails

              Quarantine; find the nondeterministic source first

              Private attribute asserted

              Rewrite against returned data

              Passes all but sentinel stays green

              Delete the test; it protects nothing

              Passes all three

              Keep; this one guards the edit

              Red after a legitimate fix

              Remove the test; characterization is not a spec


              That last row matters. Characterization tests freeze current behavior, bugs included. If the frozen behavior is a real defect, file it and delete the test.

              Limitations and who should skip this


              • The sentinel gate only catches changes your sentinel touches. Choose sentinels per behavior, not one global patch.
              • Twenty runs cannot find rare-path flakiness. Shorten the interval or widen the run count for hot paths.
              • The AST check is syntactic. Helper-mediated private access passes it.
              • Model-drafted tests encode the model's reading of your output. Paste raw observations, not summaries.
              • Skip this if the target module has no runnable entrypoint. Build one first; gates need something to run.
              • Skip it for a module you are actively rewriting anyway. Gates pay off on code you intend to keep.

              If you want to try the drafting step without spending anything, run the prompt contract against a free model, then let the three gates decide what survives. The gates are the part worth keeping.
              A Test That Cannot Fail Is Decoration: Gating Model-Drafted Characterization Tests

                #refactoring boosted

                [?]Dev Community » 🤖 🌐
                @devto@www.urbanmind.net

                A green characterization suite is not evidence of safety. It is a claim. Verify the claim before you cut anything.

                Most refactors fail in the same way. The pins pass before the change. The pins pass after the change. Then a downstream job breaks, because the pins never actually watched the behavior you moved. You need a score for the net itself.

                This post covers one measurable gate: mutation-check the pins first, then make the smallest safe change. Earlier posts in this series built the pins. This one asks whether they can fail.

                Two ways a pin suite lies to you


                The blind pin. It asserts something stable and irrelevant. assert result is not None passes forever, including after you delete half the report.

                The tautological pin. It copies the implementation into the test. It imports private helpers and asserts the same call order the source already has. It fails when you rename, not when you break.

                Both produce green CI. Neither produces a safety net. Coverage numbers will not tell you which one you have.

                The artifact: a pin sensitivity score


                This harness applies small text-level mutations to the source, then runs the pin suite against each mutant. A good net catches most mutants. A decorative net catches none.

                Save as pin_check.py. Exit code 0 means the score cleared your threshold.

                python3
                """Measure characterization-pin sensitivity with text-level mutations.

                Usage:
                python pin_check.py --repo . --min-score 0.6 \
                --pin-cmd "python -m pytest -q tests/pins"

                Exit codes: 0 = score >= min-score, 1 = below threshold, 2 = harness error.
                """
                from __future__ import annotations

                import argparse
                import json
                import shutil
                import subprocess
                import sys
                import tempfile
                from dataclasses import dataclass, asdict
                from pathlib import Path

                @dataclass(frozen=True)
                class Mutation:
                name: str
                rel_path: str
                old: str
                new: str

                # One row per behavior you believe the pins protect.
                # Text-level on purpose: cheap, reviewable, no AST tooling required.
                MUTATIONS: tuple[Mutation, ...] = (
                Mutation("currency_default", "billing/invoice.py",
                'currency: str = "USD"', 'currency: str = "EUR"'),
                Mutation("round_precision", "billing/invoice.py",
                "round(total, 2)", "round(total, 1)"),
                Mutation("skip_none_rows", "billing/report.py",
                "if row is None:", "if not row:"),
                Mutation("sort_key", "billing/report.py",
                "key=lambda r: r.date", "key=lambda r: r.amount"),
                Mutation("header_order", "billing/report.py",
                '["id", "date", "amount"]', '["date", "id", "amount"]'),
                )

                IGNORE = shutil.ignore_patterns(".git", "__pycache__", "*.pyc", ".venv")

                def run(cmd: list[str], cwd: Path) -> int:
                proc = subprocess.run(cmd, cwd=cwd, capture_output=True, text=True)
                return proc.returncode

                def apply_mutation(root: Path, mut: Mutation) -> bool:
                target = root / mut.rel_path
                if not target.exists():
                return False
                src = target.read_text()
                if mut.old not in src:
                return False # stale pattern: refresh this row
                target.write_text(src.replace(mut.old, mut.new, 1))
                return True

                def check(repo: Path, pin_cmd: list[str]) -> dict:
                baseline_exit = run(pin_cmd, repo) # pins must be green on pristine tree
                caught = applied = 0
                detail: list[dict] =

                [] for mut in MUTATIONS:
                with tempfile.TemporaryDirectory() as tmp:
                work = Path(tmp) / "repo"
                shutil.copytree(repo, work, ignore=IGNORE)
                if not apply_mutation(work, mut):
                detail.append({"mutation": mut.name, "status": "stale-pattern"})
                continue
                applied += 1
                hit = run(pin_cmd, work) != 0
                caught += int(hit)
                detail.append({"mutation": mut.name,
                "status": "caught" if hit else "missed"})

                score = caught / applied if applied else 0.0
                return {"baseline_exit": baseline_exit, "applied": applied, "caught": caught,
                "score": round(score, 2), "detail": detail}

                def main() -> int:
                ap = argparse.ArgumentParser()
                ap.add_argument("--repo", default=".")
                ap.add_argument("--pin-cmd", required=True)
                ap.add_argument("--min-score", type=float, default=0.6)
                args = ap.parse_args()

                report = check(Path(args.repo).resolve(), args.pin_cmd.split())
                print(json.dumps(report, indent=2))

                if report["baseline_exit"] != 0:
                print("harness error: pins already fail on the pristine tree", file=sys.stderr)
                return 2
                return 0 if report["score"] >= args.min_score else 1

                if __name__ == "__main__":
                raise SystemExit(main())

                The mutation list is the actual deliverable. Each row is a belief you are testing. Add a row every time a reviewer asks "but does this break X?"

                Step 1: Confirm the pristine tree is green


                Run the pins alone first. A failing baseline invalidates the whole measurement.

                python -m pytest -q tests/pins # must exit 0
                python pin_check.py --repo . --min-score 0.6 \
                --pin-cmd "python -m pytest -q tests/pins"

                Expect baseline_exit: 0. Expect a detail array. Expect missed rows. The misses are the point.

                Step 2: Read the score as a gate, not a grade


                The number is a threshold check. Use it to decide whether to start, not to celebrate.

                Score

                Reading

                Action

                0.0 - 0.2

                Pins are decorative

                Do not refactor. Pin public outputs of the entry points first.

                0.3 - 0.5

                Blink spots cluster

                Open the missed rows. Add one output-level pin per cluster.

                0.6 - 0.8

                Usable for a bounded change

                Proceed with one behavior-preserving step only.

                0.9 - 1.0

                Possibly over-pinned

                Grep for private imports. Trim pins that fail on rename.


                A high score is not automatically good news. Suites that pin every internal call also score well. They just cost you every future rename.

                Step 3: Probe for tautological pins


                Pins that import private names rarely specify behavior. They duplicate it.

                # Suspects: pins reaching into underscore-prefixed helpers.
                grep -rnE "^\s*from [A-Za-z_.]+ import _" tests/pins | tee tautology-suspects.txt
                wc -l < tautology-suspects.txt

                Review each hit. Ask one question: does this assertion describe output, or restate the source? If it restates, rewrite it against the public boundary.

                Step 4: Make the smallest safe change


                One behavior-preserving step. One commit. No drive-by cleanups, no renames.

                git switch -c refactor/invoice-totals
                # single change here only
                python -m pytest -q tests/pins # green after the change
                git stash
                python -m pytest -q tests/pins # green before it too
                git stash pop

                If the pins pass only on the changed tree, they were tailored to the change. That is a rewrite of the specification, not a verification of it.

                Where free tooling fits


                The mutation list is the slow part. Someone has to guess which behaviors matter. I use MonkeyCode's free model access to draft candidate rows from a module's recent diff history, then delete most of them by hand. The candidates are proposals only, and every row still needs a human to confirm it describes real behavior. Its free server option is useful when the pin suite is too heavy for a laptop and CI minutes are budgeted elsewhere.

                Disclosure: This article was prepared as part of MonkeyCode's product outreach.

                Treat availability, limits, and model lineups as operator-supplied and changeable. Verify current terms yourself. Do not put a free tier on a release-critical path.

                Limitations and who should skip this


                Text-level mutations are crude. They catch only a pattern that still exists verbatim. Rename a variable and the row silently becomes stale-pattern. Refresh rows when you touch the file.

                A high score does not prove correctness. It proves the net can fail on the mutations you thought of. Semantic drift outside your list stays invisible.

                If you already run a real mutation framework, use it. Tools like mutmut or cosmic-ray generate far better mutants than a hand-written list. This harness is for repos where adding one more test dependency is politically harder than adding one script.

                Skip this if the output has no stable entry point, or if nobody consumes the output. Skip it for throwaway scripts. The score only matters where a regression has a cost.

                Start with the misses


                Run the harness on your messiest module and post the missed list. The score is a gate. The misses are the map.

                One behavior-preserving change, one verified net. In that order.
                Test the Safety Net First: Mutation-Check Characterization Pins Before a Refactor

                #refactoring boosted

                [?]Dev Community » 🤖 🌐
                @devto@www.urbanmind.net

                #refactoring boosted

                [?]ainews » 🌐
                @sayzard@mastodon.sayzard.org

                Josh Marino 🦞 (@AIRoboticsInt)

                Gemini 4 Argon의 최대 출력 길이가 기존 64K에서 100만 토큰으로 확대됐다는 내용이다. 멀티파일 애플리케이션 생성이나 대규모 리팩터링을 한 번의 응답으로 처리할 수 있는 규모이며, 얼리 액세스 사용자는 긴 작업에서 중도 포기가 적었다고 평가했다. 다만 3D 작업 성능 평가는 유보해야 한다고 언급했다.

                x.com/AIRoboticsInt/status/211

                  #refactoring boosted

                  [?]Dev Community » 🤖 🌐
                  @devto@www.urbanmind.net

                  A late cleanup request arrived with a four-hundred-line diff that rewrote validation, deduplication, and persistence in one pass. The existing tests covered only the happy path, so a green CI run could not explain the legacy rows. The reviewer needed a smaller change that preserved every observed output before any structural boundary was allowed to move. This composite scenario shows how to freeze those outputs, then accept only the smallest safe edit.

                  The module under review is a batch upload normalizer that grew by successive tickets rather than by design. It reads a list of records, fills missing defaults, drops exact repeats, and writes survivors to storage. Those four jobs share one function, so a cleanup that touches all of them cannot be reviewed as one claim. The method below separates observation from edit, and it does not depend on any particular assistant.

                  Name the behavior you will freeze


                  Before changing code, write down the inputs that already matter and the outputs you are willing to treat as current truth. Include awkward rows from production samples, not only the tidy examples attached to the latest ticket. A characterization file is a pinned record of those pairs, not a statement that the behavior is desirable. If a row is known to be wrong, mark it as accepted debt instead of silently correcting it during the same change.

                  Three observations keep the freeze honest when the repository is already messy.

                  • Record the returned list and the store payload, because a matching return can still hide a second write.
                  • Preserve the original row order, because a sort that looks cleaner can change which duplicate survives.
                  • Keep skipped rows visible in the fixture notes, because a deleted branch is still a behavior change.

                  That list is the review contract for this module, and it should stay visible in the pull request description. It is narrower than a repository-wide characterization suite, and it is not a license to rewrite neighboring helpers. This pass does not hash a repository-wide side-effect ledger, and it does not ask you to freeze every neighboring seam. The next section turns the contract into a local command you can rerun after every proposed diff.

                  Pin a fixture before the extraction


                  The following Python example is a proposed harness, not a log from a measured production run. It uses a memory store so the test process does not touch a real database or a shared queue. The cases cover a blank SKU, a negative quantity, an exact repeat, and a lowercase SKU that the current code uppercases. Run the capture against the untouched function, then commit the fixture before you accept any cleanup.

                  import json
                  from pathlib import Path

                  class MemoryStore:
                  def __init__(self):
                  self.batches =

                  [] def write(self, rows):
                  self.batches.append([dict(row) for row in rows])

                  def normalize_upload_batch(records, store):
                  seen = set()
                  kept =
                  [] for record in records:
                  sku = (record.get('sku') or '').strip().upper()
                  qty = record.get('qty', 0) or 0
                  if not sku or qty < 0:
                  continue
                  key = (sku, int(qty))
                  if key in seen:
                  continue
                  seen.add(key)
                  kept.append({'sku': sku, 'qty': int(qty)})
                  store.write(kept)
                  return kept

                  CASES = [
                  {
                  'name': 'blank-sku',
                  'records': [{'sku': ' ', 'qty': 2}],
                  'debt': False,
                  },
                  {
                  'name': 'negative-qty',
                  'records': [{'sku': 'ab1', 'qty': -1}],
                  'debt': False,
                  },
                  {
                  'name': 'case-and-repeat',
                  'records': [
                  {'sku': 'ab1', 'qty': 2},
                  {'sku': ' AB1 ', 'qty': 2},
                  {'sku': 'ab1', 'qty': 3},
                  ],
                  'debt': False,
                  },
                  ]

                  def capture(cases):
                  report =
                  [] for case in cases:
                  store = MemoryStore()
                  returned = normalize_upload_batch(case['records'], store)
                  report.append({
                  'name': case['name'],
                  'debt': case['debt'],
                  'returned': returned,
                  'written': store.batches,
                  })
                  return report

                  def main():
                  path = Path('batch_characterization.json')
                  payload = json.dumps(capture(CASES), indent=2) + '\n'
                  path.write_text(payload, encoding='utf-8')
                  print('wrote', path)

                  if __name__ == '__main__':
                  main()

                  Compare the fixture, do not skim the diff


                  A second, ordinary command compares a fresh capture with the fixture you already committed to the branch. The comparison is a textual check of the JSON, not a visual skim of a large assistant diff. If you later correct a debt row, change the fixture in a separate commit and state the product reason in that commit message. Until you trust the harness, treat a non-empty fixture diff as a failed review rather than as a suggestion.

                  Save the harness as capture_batch.py beside the fixture so the commands below match the file you run.

                  python capture_batch.py
                  git diff -- batch_characterization.json

                  The sample function above is embedded so a reader can follow the article without cloning a repository. In a real repository, import the existing function instead of pasting a simplified copy into the test file. A pasted copy can drift from the production function and then bless the wrong behavior during review. Keep the fixture next to the module so a reviewer can open both without searching the whole tree.

                  Score the smallest safe change


                  After the fixture is committed, the only edit this pass allows is an extraction of the pure selection loop. The wrapper may call the new function and then perform exactly one write to the existing store. It may not add a sort, a new skip rule, a retry, or a second store call. The table below is the acceptance gate for the diff, and a single failed row is enough to reject the change.

                  Check

                  Accept this pass

                  Send it back

                  Files touched

                  The one module that owns the batch function

                  Any helper outside that file

                  Fixture JSON

                  Unchanged after a local rerun

                  Any added, dropped, or reordered field

                  Store writes

                  One write, matching the returned rows

                  An extra write, a cleared batch, or a write before selection

                  New branches

                  None

                  A fallback, a retry, or a temporary compatibility flag

                  Debt rows

                  Still marked debt in the fixture

                  Quietly corrected inside the cleanup

                  The extraction that the gate allows


                  The extracted shape that satisfies every row of the table looks like the unexecuted sketch below. It remains a proposal until you rerun the capture and the fixture diff is completely empty. Notice that the skip rules are copied, not improved, because an improvement is a behavior change and belongs in a later commit. The wrapper stays responsible for the write, so persistence bugs are not mixed into the pure move.

                  def select_upload_rows(records):
                  seen = set()
                  kept =
                  [] for record in records:
                  sku = (record.get('sku') or '').strip().upper()
                  qty = record.get('qty', 0) or 0
                  if not sku or qty < 0:
                  continue
                  key = (sku, int(qty))
                  if key in seen:
                  continue
                  seen.add(key)
                  kept.append({'sku': sku, 'qty': int(qty)})
                  return kept

                  def normalize_upload_batch(records, store):
                  kept = select_upload_rows(records)
                  store.write(kept)
                  return kept

                  Follow the same four steps


                  1. Commit the characterization fixture that you generated from the untouched function before any extraction work begins.
                  2. Extract only the selection loop into a pure helper, and leave the storage write inside the original wrapper.
                  3. Rerun the local capture after that extraction and require an empty diff on the committed fixture file.
                  4. Schedule debt corrections, retries, and storage changes as later commits that carry their own expected results.

                  That order matters more than the size or brand of the assistant that happened to propose the cleanup. A small extraction can still be wrong if you regenerate the fixture after the edit and then treat the new file as the baseline. Commit the baseline first, or the acceptance gate has nothing stable left to protect later. If step three fails, restore the extraction and inspect the case, rather than widening the diff to force a match.

                  Let an assistant draft, then keep the gate local


                  Disclosure: This article was prepared as part of MonkeyCode's product outreach.

                  A coding assistant can draft fixture cases or the extraction sketch after you have already named the rows you care about. For this draft, the operator supplied two availability claims: free model access and a free server option. This article does not state model names, token quotas, hardware size, duration, or benchmark scores, because those details were not provided as primary sources. Check the project documentation on the day you start, because availability terms can change and should not be copied from an older post.

                  The useful split should stay small even when the assistant is allowed to see the whole repository. Ask it to propose cases that match the contract, then paste those cases into the harness and run the capture yourself. Ask for the extraction only after the fixture is committed, and reject any diff that fails a row in the table. A free server can be a convenient place to run that capture when your laptop cannot match the language version. The committed fixture still belongs in the repository you review, not only on the temporary machine.

                  If that gate matches how you already review cleanups, read the current access notes before you try it. Then run the same fixture workflow on one module you can execute on a machine you control. Keep the product optional: the harness, the table, and the empty fixture diff are the parts a teammate can reuse without an account. A reviewer should never treat a model-written explanation as proof that the fixture file remained stable.

                  Limitations and who should skip this


                  This approach freezes current behavior, including bugs that nobody has yet scheduled for a product fix. It is a poor fit when the ticket requires a visible behavior change inside the same pull request. It is also a poor fit when you cannot obtain representative rows, because an empty fixture will bless whatever the first draft happens to emit. A memory store does not prove transaction order, locking, or partial failure, so do not use it to clear a data-migration change.

                  Skip the gate as your only review when the diff touches authentication, billing totals, or deletion. Those areas need explicit expected outcomes, not a snapshot of whatever the old code already did. Do not plan a team rollout around an unverified free quota or an assumed server lifetime from an old post. If today's documentation does not confirm the access terms you need, treat the assistant as optional. Keep the harness on a machine you control rather than on a shared environment you have not reviewed.

                  The closing claim stays modest, and a reviewer can audit it from the fixture diff alone. A four-hundred-line cleanup becomes reviewable when one characterized seam moves and the fixture file stays still. Everything else can wait for a later commit that states the behavior it intends to change. That later commit should carry its own cases, rather than borrowing the freeze you used to keep this extraction honest.
                  Require an Empty Fixture Diff Before Extracting a Batch Loop

                    #refactoring boosted

                    [?]Dev Community » 🤖 🌐
                    @devto@www.urbanmind.net

                    When an agent renames a symbol, it updates every import it can see. It skips every reference that lives inside a string — and that is exactly where the breakage shows up at 2am.
                    Your Agent Renamed the Function — It Just Missed the Caller That Referenced It by String

                      #refactoring boosted

                      [?]United Kingdom News Beep » 🌐
                      @uk@newsbeep.org

                      Agents Refactor 300K Lines in Three Weeks, and Practitioners Ask What It Proves

                      CodeScene has published a case study in which coding agents refactored a 300,000-line C codebase over three weeks,…
                      &Design &DataEngineering
                      newsbeep.com/uk/787296/

                        #refactoring boosted

                        [?]ainews » 🌐
                        @sayzard@mastodon.sayzard.org

                        BOOTOSHI 👑 (@KingBootoshi)

                        에이전트 기반 코드 생성에서는 초기 구현의 완성도보다 먼저 동작하는 기능을 빠르게 만든 뒤 리팩터링하는 2단계 워크플로가 고품질 코드로 이어진다는 주장이다. 모델이나 복잡한 워크플로보다 실행 가능한 초안을 우선 확보하는 방식에 초점을 둔다.

                        x.com/KingBootoshi/status/2104

                          Back to top - More...