DynoInvoice · Traceability · Anatomy

One requirement, and everything recorded about it.

Tickets close and chats scroll away. In Keel, a requirement stays connected to its acceptance criteria, the tasks cut from it, every question raised along the way and who answered it, every reviewed change, and the code and tests that implement it. This page opens one DynoInvoice requirement, INV-REQ-738, and lays all of that out.

In plain words: when an invoice names a buyer or seller, DynoInvoice marks whether that party is in the same GST group, or in the same customer account. Whether supplies inside a GST group must be reported is still a question for a tax adviser, so the rule for them ships marked provisional, and a data release can change it without a code change.

THIS REQUIREMENT AT A GLANCE · 26 OCTOBER 2026
5published revisions
4acceptance criteria
4tasks, all merged
16design questions: 1 answered by the owner, 14 ruled by the coordinating agent, 1 waiting on a tax adviser
3of those rulings made from an earlier ruling
5must-fix review findings, across 2 merge requests
1change sent back by the examiner, with 4 findings
8public commits; 3 tests that name its criteria
From the Keel record and the public repository at 26 October 2026, 00:00 SGT.

How the records connect

Every box below is a record you can open, and every arrow is a link Keel stores. Questions block the tasks that raised them; answering a question publishes a reviewed change that revises the requirement or the task; tasks become merge requests; merge requests become commits; tests carry the key of the criterion they prove.

Requirement1, five published revisions
→
Acceptance criteria4
→
Tasks4, each with done-when criteria
→
Design questions16, each with a recorded answer or waiting
→
Reviewed changesexamined before publishing
→
Merge requests4, independently reviewed
→
Commits8 on the public repository
→
Tests3 named after the criteria they prove
The links, as Keel stores them
INV-REQ-738 -has_criterion-> INV-AC-760, INV-AC-761, INV-AC-1823, INV-AC-2783
INV-REQ-738 -refines-> INV-REQ-720, INV-REQ-44
INV-REQ-738 -decided_by-> INV-ADR-2778
INV-T-4912, INV-T-6503, INV-T-8434, INV-T-4943 -implements-> INV-REQ-738
INV-T-4943 -implements-> INV-AC-760, INV-AC-1823
INV-T-4912, INV-T-6503 -implements-> INV-AC-761
INV-T-4968 -implements-> INV-AC-761, INV-AC-2783   (waiting on a dependency)
INV-Q-8421, 8423, 8425, 8427, 8480, 8482, 8484, 8486, 8513 -blocks-> INV-T-4943
INV-CS-8432 -resolves-> INV-Q-8421, 8423, 8425, 8427
INV-CS-8487 -resolves-> INV-Q-8480, 8482, 8484, 8486
INV-Q-8427 -ruled_by_precedent-> INV-Q-3324
INV-Q-8486 -ruled_by_precedent-> owner ruling, 22 October
INV-CS-8432 -changed-> INV-REQ-738 (revision 14), INV-T-4943
INV-T-4912 -merged_as-> platform-contracts !57 -> d49bed5e, b77af3a8
INV-T-6503 -merged_as-> platform-contracts !136 -> 199b454d
INV-T-4943 -merged_as-> svc-masterdata !2 -> 1de1ed9f, cfe12822, 23cf7c8c, f1e61905, 07e79ef3
INV-AC-760 -tested_by-> CounterpartySamenessTest (1 test)
INV-AC-1823 -tested_by-> CounterpartySamenessTest (3 tests)

1 · The requirement

INV-REQ-738 · revision 14
“Counterparty resolution MUST flag sameGroup and sameTenant. The scope pack MUST contain a parameterised rule for intra-group supplies, set provisional until INV-Q-2835 is answered.”

Its behaviour, as now written: master data sets both flags; the rules pack holds the intra-group rule, marked provisional and labelled as inferred; an in-group document is scoped on its own category, like a third-party one, and carries the flag so it can be reprocessed later; both flags are derived from organisation-structure events, with no synchronous call to another service.

It has been published five times. Each revision is a reviewed change with a reason:

RevisionDateChangeWhat changedWhy
624 SepINV-CS-682First published formPart of the domain batch built from the source documents; the owner approved the batch
825 SepINV-CS-2731Phase moved from wave 4 to wave 2The owner ruled that waves are build-dependency layers for agents (INV-ADR-2732)
1226 SepINV-CS-2777“Provisional” narrowed to the group flag only; criterion INV-AC-2783 addedLow-confidence rulings from the import were re-decided (INV-ADR-2778)
1322 OctINV-CS-8370Readiness slots filled; text unchangedRuling INV-Q-8368
1422 OctINV-CS-8432Behaviour 4 and a data-model sentence addedRuling INV-Q-8427, after a coding agent stopped to ask

2 · Acceptance criteria and the tests that prove them

CriterionWhat it requiresProved by
INV-AC-760Two entities of one customer account trade with each other: both sides are recorded and paired, with no collisionTest 1 checks the flags; pairing itself belongs to another requirement
INV-AC-761An in-group standard-rated supply is in scope and an out-of-scope one is not, the same as for a third party; the rule shows it is inferredContract half merged (scope-pack-contents.schema.json); its test waits on a rules-service task
INV-AC-1823X and Y in one GST group, Z in the same account but outside the group: Y gets both flags, Z only the account flagTests 1, 2 and 3
INV-AC-2783An in-group standard-rated supply is submitted with a warning (GST Act s30(2)), not blockedWaits on the same rules-service task

The three tests live in CounterpartySamenessTest.kt, and each name carries the criterion key, which is how the build checks coverage:

INV-AC-1823 INV-AC-760 resolution sets sameTenant and sameGroup from the structure events
INV-AC-1823 a retired node, a lower structure version and a group without a GSTN are read as the rules say
INV-AC-1823 a node of another tenant with the same UEN gives neither flag

The service’s ac-keys.tsv lists INV-AC-760 and INV-AC-1823 against task INV-T-4943; a gate fails the build if a listed criterion has no test with its key. The two criteria still waiting for tests stay open in Keel until their task is done.

3 · Four tasks

Agents cut four tasks from this requirement. Two of them exist only because a coding agent stopped and asked: the questions it raised turned into new work instead of guesses.

INV-T-4912

Complete the master-data contract

Done when: new optional fields for the group and account flags and related data, with valid and invalid samples; the breaking-change check must report additive changes only.

Implements this requirement and nine others. Merged 15 Oct after review found a missing required list, missing invalid samples and a wrong reversibility flag.

Commits: d49bed5e, b77af3a8

INV-T-6503

Schema for the rules-pack contents

Done when: five required sections, including the intra-group rule with its provisional flag, proved by valid and invalid samples.

Merged 18 Oct; the reviewer re-ran every sample and three fail-closed probes.

Commits: 199b454d

INV-T-8434

Architecture-model change

Done when: the master-data service consumes organisation-structure events; the model’s consistency check passes and fails on planted faults.

Created when a coding agent stopped on INV-T-4943. Lives in the design repository, which is not mirrored.

Commits: —

INV-T-4943

Counterparty master in the master-data service

Done when: resolve a counterparty with block, hold or warn findings; keep identifier provenance and history; derive both flags from the service’s own structure table; publish the resolved event; refuse an entity outside the caller’s scope.

Merged 22 Oct. That day the coding agent stopped three times, each time on questions that were ruled before it resumed.

Commits: 1de1ed9f, cfe12822, 23cf7c8c, f1e61905, 07e79ef3

Each task owns rows in the service’s operations.tsv; an operation owned by a finished task must not answer “not implemented”.

4 · Sixteen design questions, and who answered them

Questions about functionality and direction go to the product owner. The coordinating agent rules the rest when the answer is clear-cut, citing a named practice or an earlier ruling. Here is how this requirement’s questions went.

INV-Q-4874 · Owner, recommendation not taken

Early contracts lacked fields later work needed: how should they be completed if contracts are “frozen” early? The agent recommended follow-up tasks. The owner chose otherwise: “Contract-first means the contract is settled first, then implemented; it does not require completion in the first wave. Contracts are supplemented when they are needed.” Task INV-T-4912 exists because of this answer.

INV-Q-2835 · Open, waiting on a tax adviser

Must supplies inside a GST group be reported? Nobody inside the project can settle this, so the rule ships provisional and the question stays visibly open.

INV-Q-1736 · Coordinating agent

How to scope in-group supplies: pass them through as for a third party, marked provisional. Re-decided two days later to narrow “provisional” to the group flag and add a warning rather than a block, citing GST Act s30(2).

INV-Q-8427 · Coordinating agent, by precedent

Where do the flags come from? From a read model the service owns, fed by structure events, following an earlier ruling on version ordering (INV-Q-3324) and the published rule that this service makes no outward calls. A synchronous call to the tenancy service was rejected.

INV-Q-8486 · Coordinating agent, by precedent

No operation existed for the ingestion service to write counterparties: add one on the existing edge, following the owner’s ruling of 22 October that “who may call whom, and when, must follow the system architecture design, not a mechanical judgement.”

INV-Q-5203 · Coordinating agent, by precedent

Six contract-shape choices, each copied from a sibling contract: “every choice has a published precedent.”

INV-Q-8368 · Coordinating agent

Eleven requirements lacked criteria, so the task could not be marked done. Ruling: write the criteria. A waiver was rejected, because “a waiver of a check is the owner’s.”

INV-Q-8513 · Coordinating agent

Where should the “outside your scope” refusal come from? One generic filter driven by the contract. Inferring it from property names was rejected: “a guess in a security filter fails open or over-refuses.”

The other eight (INV-Q-5189, 6492, 8421, 8423, 8425, 8480, 8482, 8484) were ruled by the coordinating agent with a named reason, most of them on the day a coding agent stopped to ask.

5 · Checks on the work itself

The examiner sent a change back

A revision of task INV-T-4943 (INV-CS-7893) came back with four findings: a line still cited a removed criterion; “the set the policy port holds” named no set, so it couldn’t be verified; a criterion said no merge request existed when one did; and an example used a request body the service now refuses. All four were fixed and approved four minutes later.

The reviewer blocked two merges

On the contract, a request body had no required list and invalid samples were missing (fixed in b77af3a8). On the service, an operation took six parameters where the standard allows five; the finding said to group them into a value type and “do not add a suppression or a baseline entry”. A dependency-verification gap was also fixed (f1e61905, 07e79ef3).

Across the four merge requests: eight review threads, five of them must-fix; two needed a fix round. On the two that passed first time, the reviewer re-ran the samples and planted a fault to confirm the checks catch it.

What this shows

Nothing here was reconstructed for this page. The requirement, its five revisions, the sixteen questions and their answers, the reviewed changes and the links between them are records in Keel; the code, tests and commits are in the public repository. A coding agent picking up any of these tasks, or a person asking in six months why the group flag is provisional, gets the same answer from the same record.

That is what we mean by governing requirements rather than managing code: the requirement is the source of truth, and the code is a mapping of it that can be checked.

More: when green isn’t enough · why does this line exist? · reviewing like an attacker · when the spec runs out · eight shorter traces from requirement to merged code · when a decision changes · the DynoInvoice repository