Skip to content

fix(harness): keep reading_inputs through every re-save of a seeded contract (TH-8952) - #296

Open
khushalsonawat wants to merge 2 commits into
feat/TH-8804-source-subfolderfrom
fix/TH-8952-seed-keeps-reading-inputs
Open

khushalsonawat wants to merge 2 commits into
feat/TH-8804-source-subfolderfrom
fix/TH-8952-seed-keeps-reading-inputs

Conversation

@khushalsonawat

@khushalsonawat khushalsonawat commented Nov 11, 2026 •

Copy link
Copy Markdown
Member

Into feat/TH-8804-source-subfolder, where #269's seed contract is (it isn't on dev yet).

Summary

Dileep's end-to-end run on an uploaded folder found that a seeded build's final contract had lost reading_inputs. The seed was taken and understanding was skipped, but a later step rewrote contract.json without the key. The platform decides "seeded" by that key, so it kept the reading's contract. The GitHub path kept the key only because no re-save happened to run after the seed there; nothing in the code protected it.

Every save of the contract goes through contract.write_contract, which writes AgentContract.model_dump(). The record isn't a model field, so each re-save dropped it: the runtime-plan repair, the data-store repair, submit_contract, and the amend tools (declare_tool, nudge, the source-facts refresh).

Now write_contract keeps the record: when the contract already saved at the destination holds reading_inputs, the new save writes it back, first, with the same value. A save where none is held writes none. No model field is added, so the schema the model sees and the repair's contract hash are unchanged. An unexpected error reading the old file is logged by class name and the save goes on.

runtime.dockerfile going from "Dockerfile" to "" is the runtime-plan repair doing its job, seeded or not. An upload with a Dockerfile and no Compose file is refused as runtime_dockerfile_unsupported in the process lane, which starts the repair, and the repaired runtime has no Dockerfile. A probe reproduces it, and the reviewer re-ran it. Nothing is changed for it.

Ticket: TH-8952. No platform change is needed.

Tests

  • test_seed_contract.py: on the upload path (archive_artifact_id), the seed is installed with use_seed, then each re-save runs (the runtime-plan repair, the data-store repair, submit_contract, add_rule, declare_tool, the nudge's stale-reference drop, the source-facts refresh), and reading_inputs survives each one unchanged. One row runs the same on the GitHub path.
  • A contract with no record gains none after each re-save; a reading's own saves hold only the record the reading put in; a build whose seed was taken back saves no record; an unreadable old file is logged.
  • test_contract_writer.py: the writer keeps a record and writes none where there was none.

Known limits

  • The record is kept JSON-equal, not byte-equal: a re-save writes it indented. The platform's and the seed check's comparisons are on JSON values.
  • On this base an upload can't carry a subfolder (subfolder_requires_github_source), so the upload rows have none.

Review

  • One worker, then one cold change reviewer: CLEAR, three Lows, all fixed here (the logged read error, the seed spec's used sentence, the take-back test).
  • The reviewer traced and probed that no build can now gain a record it didn't have: the record is added only in reading mode, which the build command refuses to combine with a seed. A take-back, a mismatch and a rejected seed install nothing, and the build's own save then writes no key.
  • Planted bugs, each failing a named test: no carry; a record carried where none was on disk; the record placed last; the seed's key not wired to the writer's; the last record carried across folders; a read error dropped silently.

Verification

  • Fix-only check pending for 67a99e52 (Dileep's P3: the read error logged with its trace).
  • On 67a99e52, Python 3.12.3: test_seed_contract.py and test_contract_writer.py, 177 passed.
  • Where the tests run: CI's SDK smoke runs test_seed_contract.py on every push. test_contract_writer.py and the runtime files ran locally on Python 3.12.3, as listed; adding test_contract_writer.py to the smoke list is pending its run on the base.
  • Fix-only check pending (two reviewers) for the three Lows applied after the change review cleared: the logged read error in _saved_record, the spec sentence (seed-contract 0.9 S4) and the two tests.
  • Python 3.12.3: test_seed_contract.py 126, test_contract_writer.py 51, test_runtime_repair.py 213, test_runtime_repair_decision.py 3, test_authoring_runtime_validation.py 112 passed.
  • ruff check clean on the changed files; lines wrapped at 99.
  • Logs carry a class name only, never a value.

…ontract (TH-8952)

Every save of contract.json goes through write_contract, which wrote only the model's
fields. reading_inputs isn't one, so a re-save after the seed (the runtime-plan repair,
the data-store repair, submit_contract, the amend tools) dropped it, and the platform,
which reads the key as "seeded", kept the reading's contract instead.

write_contract now keeps the record held by the contract already saved at the
destination, first and with the same value; a save where none is held writes none. No
model field is added, so the schema and the repair's contract hash are unchanged. An
unexpected error reading the old file is logged by class name and the save goes on.

Tests run the seed on the upload and GitHub paths, then each re-save, and check the key
survives; a contract without a record, a reading's own saves, and a build after a
take-back gain none.

TH-8952

Signed-off-by: khushalsonawat <khushalsonawat@gmail.com>

@cdileep23 cdileep23 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check the comments.

Comment thread src/fi/alk/harness/contract.py Resolved
… its trace (TH-8952)

A contract.json that can't be read back drops the reading record, so the
save turns a seeded build into an unseeded one. Log the error with its
traceback, not the class alone, and say why in the comment.

Signed-off-by: khushalsonawat <khushalsonawat@gmail.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants