Product ThinkingThe Blog
A Document Should Enter a System, Not Disappear After Generation
Generating a contract is an event. The document should outlive the screen that created it.
Contents9 sections
- The success screen was a dead end
- The contract now has an address
- Saving can fail after generation succeeds
- I called the records immutable, then changed the rule thirty-six minutes later
- Drafting now leaves a footprint
- A history is not a ledger
- Memory creates policy
- The smallest useful lifecycle
- Generation should create something the product can remember
From the WALDHORN.AI Build Archive
Build date: May 24, 2026
Today I added a feature that sounds almost too obvious to deserve a feature announcement.
Generated contracts now remain in WALDHORN.AI after they are generated.
Until this afternoon, the product could do a fairly substantial piece of work and then behave as though it had no memory of doing it.
A user could spend time defining the deal, generate a full agreement, read the result, and leave the page.
The contract existed.
The system did not really know that it existed.
At 4:26 PM, I changed that.
The success screen was a dead end
Generative software naturally wants to organize itself around a single moment.
Input goes in. Computation happens. Output appears. Success.
That is a reasonable shape for a product when the output is disposable.
Ask a question, get an answer, move on.
A contract does not fit that pattern very well.
The useful life of an agreement begins after it has been created. Even without building anything sophisticated around it, I know someone may want to reopen the same document tomorrow, find it two weeks later, confirm which parties it concerned, or make sure the agreement in front of them is the one they actually generated.
None of those needs requires AI.
They require memory.
So a successful generation now creates a saved contract record under the user's account.
The output no longer belongs only to the browser session that produced it.
It has somewhere to go.
The contract now has an address
The first version is intentionally simple.
A saved agreement carries the generated document, its reference, creation time, available party information from the drafting session, and the model associated with the generation.
I added a Contracts section to the workspace.
Open it and the agreements appear newest first. Each row can show the agreement title, parties, reference and date. Select one and WALDHORN.AI reopens the saved contract in a read-only view using the same renderer that displayed it immediately after generation.
The dashboard now also shows the most recent agreements.
There is no new AI capability in any of this.
That is partly why I like the change.
The drafting model did not become smarter today. The contract did not become more sophisticated. I did not add another visible piece of intelligence to the generation flow.
I gave the result an identity and a place.
A generated contract that exists only on a success screen is output. A contract the system can find again is a record.
Saving can fail after generation succeeds
Persistence immediately creates an awkward question.
What happens if the contract generates successfully, but saving it fails?
Right now I treat those as two different events.
Once generation succeeds, the contract remains visible to the user. WALDHORN.AI then shows a small persistence state: Saving..., followed by Saved to history when the write succeeds.
If saving fails, the successfully generated agreement does not disappear.
That is deliberate.
The user has already waited for the generation and received a valid result from that process. A storage error afterward should not retroactively turn that result into nothing.
The tradeoff is that a contract can theoretically exist on screen without making it into history.
I do not love that failure mode.
I prefer it to destroying the successful output because a second operation failed.
This is one of those small engineering choices that exposes how vague the word success can be.
Generation succeeded.
Persistence did not.
The interface should be able to tell the truth about both.
I called the records immutable, then changed the rule thirty-six minutes later
The first storage version I committed made generated contracts read-only and non-deletable.
The reasoning was straightforward.
This is a legal document. If WALDHORN.AI saves one version of an agreement under a particular identity, I do not want somebody reopening that record later, changing three paragraphs in place, and leaving it under the same identity as though nothing happened.
So updates were blocked.
Deletion was blocked too.
Thirty-six minutes later, I changed the second part.
Users can now explicitly delete their own saved contracts and reviews.
I still do not want in-place editing.
But I realized that read-only and permanent are two different product promises.
A user being unable to silently rewrite a stored legal document does not automatically mean the product should refuse to let that user remove the record from their account.
So the boundary is narrower now.
While the saved agreement exists, its stored contents are not edited in place.
If the owner wants the record gone, deletion is explicit.
Read-only and permanent are not the same promise.
I am glad this question appeared immediately because words like immutable sound much stronger than the behavior they sometimes describe.
I would rather define the actual guarantee than borrow a stronger word.
Drafting now leaves a footprint
Before today, Draft was almost entirely a verb.
Choose terms.
Generate an agreement.
Read it.
Now that action leaves something behind.
That changes the shape of the workspace in a way I did not fully appreciate until I saw the list populated.
The application is no longer only a collection of things the user can ask it to do.
It is beginning to contain the objects created by those actions.
That distinction matters.
If another part of the product eventually needs to refer to an agreement, there is now an agreement to refer to.
It does not need to depend on whatever is still sitting in browser state. It does not need to ask the user to reconstruct the same context from scratch.
There is a persistent record with an identity.
I can imagine that becoming useful in several directions.
I am deliberately not designing all of those directions today.
A history is not a ledger
Some of the interface language I wrote uses the word ledger.
I think that is slightly ahead of what I have actually built.
Right now, this is a contract history.
It answers a few useful questions:
What agreements have I generated?
When did I generate them?
Who were they for?
Can I open one again?
That is enough.
A real ledger should probably know more than which documents exist. It should eventually be able to represent meaningful relationships or events around those documents.
But I do not want to design a sophisticated abstraction before the primitive underneath it has earned the complexity.
There is a tendency in software to name the mature system early and then start building features to justify the name.
I would rather do the reverse.
First make the documents persist.
Then see what real problems appear around them.
For now, a boring list of actual agreements is better than an impressive architecture for hypothetical ones.
Memory creates policy
The moment WALDHORN.AI remembers a document, storage stops being merely a technical decision.
I suddenly have policy questions.
Who can read the record?
Can it be changed?
Can it be deleted?
How much data belongs inside it?
What happens when saving fails?
What should happen when there are three contracts? Three hundred?
The first implementation answers only some of those.
Contract records are scoped under the user's account. The stored shape has field and size constraints. In-place modification is blocked. Removal is an explicit owner action.
There will almost certainly be more questions.
That is fine.
What interests me is that none of them existed when generation ended at the success screen.
A system that forgets its output does not have to decide what remembering means.
A system that remembers important documents does.
The smallest useful lifecycle
I do not want to pretend I built a contract lifecycle today.
I didn't.
There are no elaborate states attached to these records. There is no complicated chain of events. The history page is not suddenly a contract-management platform because it has rows and dates.
What I built is much smaller.
A contract is created.
It is saved.
It can be found.
It can be reopened.
It can be deliberately removed.
That is the lifecycle for now.
And I think there is value in keeping it that small until another real requirement forces it to grow.
Generation should create something the product can remember
The most interesting part of today's work is not the Contracts page.
It is the change in what generation means.
Yesterday, generation produced text that happened to represent an agreement.
Today, a successful generation can create an object inside WALDHORN.AI.
That object has an identity.
The system can retrieve it.
Other parts of the workspace can point to it.
Nothing about that is particularly advanced technology.
It is simply the point where I stopped treating the contract like an AI response.
If WALDHORN.AI is going to do anything useful with an agreement after creating it, the first requirement is almost embarrassingly basic.
The agreement has to still be there.
As of this afternoon, it is.