hamsa software
← All articles
Engineering7 min read

After the deployment is an observation

A constructed write-permission failure shows how controlled comparisons change the next decision without proving more than their evidence supports.

A magnifying glass overlaps a lined sheet, suggesting controlled inspection of the evidence behind a technical explanation.

After the release is a good place to look

The weekly report stops updating after R2, so the release is an obvious place to look. It is not yet an explanation. A changed parser, another selected credential, an account change or an unrelated fault could all fit the timing. Reverting may be a sensible way to reduce the disruption. Finding the cause asks for something more discriminating: a check whose alternative outcomes would send the investigation in different directions.

The investigation plan follows an invented service where a source read works and the destination write returns permission_denied. It is a fully specified case to reason through, not a real incident or an executed provider test. The notebook keeps observations separate from their interpretation. Running a function that prints the predetermined answers would not test the diagnostic method; the useful work is deciding what each possible result would make us check next.

Google's Effective Troubleshooting chapter describes testing explanations, considering confounding conditions and recording results, while distinguishing mitigation from investigation.[1] In this constructed case, the report should be marked stale and repeated unexamined writes avoided while the cause is checked. Those measures address the operational consequence without claiming that R2 caused the permission denial. The comparison can then examine the write boundary while users have an accurate account of the report's freshness.

Choose a test that can change the next action

Start with three plausible explanations: the transformation produces an unacceptable payload, the credential expired, or the job lacks write capability. More than one can be true. A release could alter both the parser and the selected connection. Finding a promising fault should therefore focus the next check rather than clear every other component by association. That keeps the investigation useful without requiring a complete account of the service before making any progress.

The first proposed test bypasses the new transformation with a previously accepted payload, using the same current principal, resource and relevant request conditions. If that succeeds, the changed transformation deserves closer inspection. In the constructed observation, it receives the same denial. The new payload is therefore not required to reproduce this denial. That weakens the case for fixing the parser first, but it does not prove the parser has no defect: a permission check might reject both payloads before either reaches the changed mapping.

A fresh uncached read succeeds under the verified same token identity while the write fails. That weakens simple expiry of the whole credential and turns attention towards the capabilities needed for writing. It does not make read permission stand in for write permission. A cached response, another token or a public endpoint would change even that narrower interpretation. Keep those comparison conditions in the notebook through safe references, so the next engineer can see why the read result is relevant without exposing the token itself.

Compare the job’s selected connection with its expected operations and resource access. In this case the write stage chose a read-only connection instead of the configured write-capable one. That mismatch explains a concrete obstacle at the current write boundary. Who selected it and whether R2 introduced the choice are historical questions for authorised configuration or change-history evidence. Separating them lets the owner correct a present fault while still investigating how it arrived. Editing the payload cannot grant a read-only connection write authority, so another round of parser changes would leave this obstacle in place. The configuration comparison earns priority for that concrete reason.

Keep the comparison conditions under control

A known-good payload is only a useful comparison when its important conditions are known too. An older payload submitted to a different account can succeed for a reason unrelated to its contents. An engineer's personal token may have broader rights than the scheduled job. A test from a laptop can take another network route. Record the account, resource, client configuration and relevant request metadata, using safe references rather than secret values. The aim is to change the explanation under test while holding enough else steady that the result is interpretable.

Useful incident work rarely comes with laboratory conditions. If the only available comparison uses another account, retain that detail rather than translate its success into the API works. The result may still justify the next low-risk check. It just answers a narrower question than a same-account test would. Naming the difference now is easier than making the next investigator unlearn a confident explanation that no longer fits the conditions they encounter.

An active test write can send a notification, duplicate a report or alter a later comparison. Observation is preferable when it can adequately distinguish the explanations; otherwise a designated resource and authorised procedure are needed. This constructed plan calls no live API and expands no scopes. The read-only connection finding identifies a mismatch to review with the owner, rather than evidence that the application should request every available permission.

Record the alternative outcome before running the test. For the old-payload comparison, success would direct attention to the transformation; denial would direct attention to the common write boundary. If both results would merely lead to rerunning the same command, the test may not be answering the question claimed for it. This small habit makes a diagnostic action accountable for the information it is expected to produce. It also helps a colleague continue the investigation without repeating a check whose negative result was never written down.

Each result narrows a different explanation

Fully specified constructed investigation, not actual incident observations or executed provider tests.

Follow the labelled arrows. On a narrow screen, scroll sideways if needed.

Each result narrows a different explanationOld accepted payload still receives denial. Compare it at the same current boundary. This sends attention to the common write boundary; it does not exonerate the parser. Fresh uncached read succeeds. Verify the same token identity. Read success narrows the whole-credential-expiry explanation but does not establish write permission. The job selects a read-only connection. Compare the configured job, principal and resource grant. The owner reviews correction and change history. Service restoration still needs verification. Run a bounded approved write and verify the actual report. A test alone cannot establish that the service is restored. From Old accepted payload still receives denial to Fresh uncached read succeeds: Inspect the shared capability boundary. From Fresh uncached read succeeds to The job selects a read-only connection: Check write capability and selection. From The job selects a read-only connection to Service restoration still needs verification: Verify the actual intended outcome.Inspect thesharedcapabilityboundaryCheck writecapability andselectionVerify theactualintendedoutcomeOld accepted payloadstill receives denialCompare it at the samecurrent boundary. This sendsattention to the common writeboundary; it does notexonerate the parser.Fresh uncached readsucceedsVerify the same tokenidentity. Read successnarrows thewhole-credential-expiryexplanation but does notestablish write permission.The job selects aread-only connectionCompare the configured job,principal and resource grant.The owner reviews correctionand change history.Service restorationstill needsverificationRun a bounded approved writeand verify the actual report.A test alone cannot establishthat the service is restored.
The notebook records alternatives, assumptions and remaining proof. Present mismatch and historical cause are separate findings.

Mitigation and explanation can finish at different times

After an approved correction selects the intended connection, a bounded write may succeed. Check the actual report update before telling its readers that it is current. Success against another resource cannot supply that evidence, and restoring today’s update does not reconstruct every missed reporting period. Those are separate pieces of work. The recovery message can be clear about which is finished without waiting for the complete historical explanation. Readers may need the latest report while its owner still checks the missing periods. Keeping both states visible prevents a successful current update from quietly closing the older work the interruption left behind.

The timeline may still need investigation. A rollback could appear to fix the report because it restores the old configuration selection, even if the released parser was never involved. Conversely, a rollback might leave the current credential selection unchanged and fail to help. Preserve which component, configuration and data state each action affected. Without that record, the eventual story can become the deployment broke it and rollback fixed it, while omitting the mechanism that would prevent recurrence.

There are times when mitigation should come before a discriminating experiment. If continued processing risks corrupting data or creating external commitments, stop that damage using an understood control rather than leave the system running to obtain a cleaner diagnosis. Explain what evidence was lost or altered by the mitigation and continue afterwards. A method that insists on perfect proof while customers bear increasing impact has confused the investigation's elegance with the purpose of operating the service.

Leave an explanation somebody can challenge

The final notebook should say what was observed, which explanations remain possible, which action restored the intended behaviour and what evidence links the original change to the failure. In this constructed case, the useful finding is a wrong connection selection at the write stage. The cause of that selection is a further historical question. Keeping those sentences separate makes the account more accurate and gives the follow-up work a specific target.

The old payload still received the denial; the same-token read worked; the job selected a read-only connection. Together those results make the next action more precise than the report failed after R2. Correct and verify the intended write path, then use change history to investigate whether the release introduced the selection. Another engineer should be able to challenge that account by following the comparisons. They should not have to accept the release timing as the missing mechanism.

Working on a workflow like this? Hamsa helps finance and operations teams connect their tools and handle the exceptions, starting with one workflow.

See the Payment Operations Pilot

References & further reading

Primary sources behind this article. Living documentation may change.

  1. Google SRE: effective troubleshooting
Hamsa Jama

Practical engineering. A human perspective.

More about Hamsa Software and the person behind it. Editorial notes.

A few more things
worth a read.

Back to the reading room
Engineering7 min read

What does £240 belong to?

A readable table preserves relationships between values, row labels, column headings and actions across different ways of reading.

Engineering7 min read

When two calculations agree on the wrong answer

A shadow comparison exposes differences. Independent rule examples explain whether those differences are bugs, corrections or changed assumptions.