A framework only matters if it changes the work. Here is one ordinary task, taken through every axis in the series.
When Rāma reached the ocean, he could not cross it. Hanumān could leap; an army could not. In Vālmīki’s telling, the ocean itself advised him: among the vānaras was Nala, son of Viśvakarmā, the divine architect, and Nala could build a bridge.
Nala did not do it alone, and he did not do it in one go. Vālmīki gives the progress day by day. Fourteen yojanas (a yojana is an ancient measure of several miles) on the first day. Twenty on the second. Twenty-one, twenty-two, and on the fifth day twenty-three, reaching the far shore. Later tellings add that the stones floated because Rāma’s name was written on them. I prefer Vālmīki’s version, with its daily measurements. It reads like a project log.
This last post is my project log. One task, five days, one axis per day.
The bridge grows day by day by Vālmīki’s figures (14, 20, 21, 22 and 23 yojanas), and each day is labelled with its axis.
The task
The task is deliberately ordinary. A knowledge-graph pipeline ingests service documents and turns them into facts. We need it to support a new document type: a structured fault report that arrives as semi-structured PDF. The pipeline already handles four other types.
Before the first stone: the spec-driven baseline
This is how most good teams work today, and it is not a bad way. Plan mode means the agent proposes a plan for approval before it writes any code.
USER STORYAs a field-service engineer, I want fault reports ingested into theknowledge graph, so that I can query past faults for a component.DEFINITION OF READY- Three sample fault reports are in fixtures/fault_reports/.- The field-to-ontology mapping is agreed in SPEC-142.DEFINITION OF DONE- Plan mode: present the plan before writing any code.- A fault-report parser in parsers/, following the existing pattern.- Fields mapped to the ontology as SPEC-142 describes.- Unit tests for the three samples.- You MUST NOT change other parsers.DEFINITION OF SUCCESS- All tests pass.
The agent plans, writes the parser and the tests, and the tests pass. A reviewer reads the diff and approves it. Total time: under two hours. It works on the three samples. That is all we know.
Day 1: speed, so explore
USER STORYAs the pipeline owner, I want three parsing approaches compared on realdocuments, so that we choose by measured accuracy, not preference.DEFINITION OF READY- The full archive of real fault reports is available, read-only.- 50 hand-labelled reports are in eval/.DEFINITION OF DONE- Three parsers in separate worktrees: rule-based extraction, layout-aware extraction, and model-assisted extraction with schema-constrained output.- All three run over the full archive.- You MUST NOT edit anything under eval/.DEFINITION OF SUCCESS- One table reporting, for all three parsers, per-field precision and recall against eval/, plus cost and latency per document.
Three bets instead of one, and a measurement instead of a debate. The poison surfaces early: one approach breaks on scanned pages, another on multi-page tables. That is the churning from Part 2 doing its job.
Terms: a worktree is a separate working copy of the repository; schema-constrained output forces the model to return data in a fixed structure; precision is the share of extracted values that are correct, and recall is the share of true values that were found at all.
Day 2: altitude, so name the invariant
USER STORYAs a field-service engineer, I want every fact in the graph to be validand traceable to its source, so that I can trust an answer at a customersite.DEFINITION OF READY- SHACL shapes for all five document types are in shapes/.- Ingestion logs are readable, and any document can be replayed.DEFINITION OF DONE- A check, run on every ingestion, that validates the graph against the SHACL shapes and confirms every fact links to a page and span.- A failure blocks publication of that document's facts.- The new fault-report parser satisfies the check.- You MUST NOT edit anything under shapes/.DEFINITION OF SUCCESS- Zero SHACL violations and zero facts without provenance across a full re-ingestion of all five document types.
The task has moved from karma to dharma (Part 3). The invariant now protects all five document types, not just the new one. The plumbing this needed: access to the ingestion logs, a way to replay any document, and the shape validator wired into CI.
Terms: SHACL is a W3C language for stating rules a knowledge graph must satisfy; provenance means each fact records exactly which page and passage it came from.
Day 3: depth, so break the seed
USER STORYAs the pipeline owner, I want the parser tested against how fault reportsreally arrive, not how SPEC-142 says they should, so that real documentsdo not break it.DEFINITION OF READY- 500 real reports are sampled from the archive.- The existing parser for the closest document type is available.DEFINITION OF DONE- A description of the variation found: layouts, missing fields, languages, scan quality.- Property-based tests: for any valid report, every required field is extracted or explicitly marked missing, and no fact is emitted without provenance.- A differential test comparing overlapping fields with the closest existing parser.DEFINITION OF SUCCESS- All properties hold over the 500 samples, and every differential mismatch is either fixed or explained in writing.
This is Uddālaka’s lesson (Part 4). The spec had described the format as it was meant to be. The raw archive shows the format as it actually arrives.
Terms: property-based tests state rules that must hold for every input and let a tool generate thousands of cases to break them; a differential test runs two implementations on the same input and flags any difference.
Day 4: range, so borrow methods
USER STORYAs the pipeline owner, I want the fault-report path examined withreliability and data-engineering methods, so that failures and breakingchanges are caught before downstream teams feel them.DEFINITION OF READY- Architecture notes for the ingestion path.- A list of the downstream consumers of fault-report facts.DEFINITION OF DONE (two sub-agents, in separate contexts)- Reliability: an FMEA table for the ingestion path (failure mode, effect, detection, recovery), and a fault-injection test for each high-severity row.- Data engineering: a data contract for the emitted fields, and contract tests that fail if a field's type, cardinality or meaning changes.DEFINITION OF SUCCESS- Each fault-injection test fails with recovery disabled and passes on main. Each contract test fails against a deliberately broken field.
Methods, not personas (Part 5). Two artefacts nobody had asked for, both of which a specialist would recognise.
Terms: FMEA (failure mode and effects analysis) lists how each part can fail, the effect and how it is detected; a fault-injection test causes a failure on purpose to prove the system copes; a data contract fixes the shape and meaning of data handed to other teams, and contract tests enforce it.
Day 5: the oracle, so protect the checks
USER STORYAs the human approver, I want this week's checks protected and the changereviewed independently, so that what we merge can be trusted.DEFINITION OF READY- SHACL shapes, property tests, contract tests and fault-injection tests all pass on the branch.DEFINITION OF DONE- All four kinds of check moved into protected paths the coding agent cannot modify; changes there require human approval.- A separate review agent, given only the diff, the tests and SPEC-142, produces the strongest case that the change is wrong.DEFINITION OF SUCCESS- Every objection from the review agent is either disproved by a passing test or fixed before merge.
Rāma’s ring (Part 6). On the fifth day the bridge reaches the far shore, because now we can trust what we built.
Terms: a protected path is a folder the coding agent cannot change; any change there needs human approval.
The log
| Day | Axis | What changed | Result |
|---|---|---|---|
| 0 | Spec-driven | Parser and unit tests for 3 fixtures | [Time; defects found later] |
| 1 | Speed | 3 parsers measured on the real archive | [Chosen approach; precision and recall] |
| 2 | Altitude | SHACL conformance and provenance as an invariant for all types | [Existing violations found in other parsers] |
| 3 | Depth | Property and differential tests from 500 real documents | [Variants found that the spec missed] |
| 4 | Range | FMEA with fault-injection tests; data contract | [High-severity failure modes found] |
| 5 | Oracle | Protected checks; independent review agent | [Issues raised by the review agent; review time] |
What the bridge was for
Rāma did not build the bridge. Nala did, with the vānaras carrying the stones. Rāma’s part was to know why it mattered, to ask for something that seemed impossible, and to accept nothing less than a bridge that would hold an army.
That is roughly where I think engineers now stand. The agents carry the stones, faster and in greater numbers than we ever could. Our work is to know what the crossing is for, to ask boldly, and to build the instruments that tell us, with a pramāṇa and not just a promise, that the bridge will hold.
We started this series with a question from the Nyāya tradition: kena pramāṇena? By what means do you know? It turns out that in agentic coding, that question is not a brake on ambition. It is what makes ambition safe.
For the Weekend
Pick one ordinary task/goal from next sprint. Run it the spec-driven way first. Then give it five days (or five milestones), one axis each, and keep a log.
Example. Suppose next sprint’s task is “add CSV export to the audit-log screen” in an internal admin application.
Day 0, spec-driven baseline.
USER STORYAs a compliance officer, I want to download the audit log I am viewing asa CSV, so that I can attach it to an investigation.DEFINITION OF READY- The audit-log screen and its filter API exist.DEFINITION OF DONE- Plan mode: present the plan before writing any code.- A "Download CSV" button on the audit-log screen.- GET /audit-log/export.csv returns the rows matching the current filters, with the same columns as the table.- Tests added.DEFINITION OF SUCCESS- All tests pass.
An agent ships it in an afternoon. Two tests pass. Log it and move on.
Day 1, speed: build the alternatives and measure.
USER STORYAs the tech lead, I want two export designs measured at productionscale, so that we choose one on evidence.DEFINITION OF READY- A staging copy with 2 million audit rows.DEFINITION OF DONE- In two worktrees: (a) streaming the CSV row by row from a database cursor; (b) a background job that writes the file to object storage and emails a link.DEFINITION OF SUCCESS- One table giving, for both designs: time to first byte, total time, peak memory, and behaviour when the user closes the tab halfway.
Day 2, altitude: name the invariant. The real requirement is not “a CSV”. It is that the export always matches what the user saw:
import csv, iofrom hypothesis import given, settingsfrom tests.strategies import audit_filterssettings(max_examples=200)given(f=audit_filters()) # random combinations of user, action, date range, text searchdef test_export_matches_screen(client, f): screen = client.get("/audit-log", params={**f, "all": "true"}).json()["rows"] body = client.get("/audit-log/export.csv", params=f).text exported = list(csv.DictReader(io.StringIO(body))) assert [r["event_id"] for r in exported] == [r["event_id"] for r in screen]
Day 3, depth: start from raw material.
USER STORYAs a compliance officer, I want exports that open safely and correctly inany spreadsheet, so that no value is corrupted or executed.DEFINITION OF READY- The masked production snapshot is available.DEFINITION OF DONE- 10,000 real audit-log rows pulled, and every value that could break a CSV or a spreadsheet identified: commas, quotes, newlines inside fields, non-Latin names, very long values, and anything starting with =, +, - or @.- Those rows added to the test fixtures.- A differential test comparing our CSV with Python's standard csv module for the same rows.DEFINITION OF SUCCESS- The differential test passes on all 10,000 rows, and no exported cell begins with a formula character.
This surfaces formula injection. A value such as =HYPERLINK(...) in a user name becomes a live formula when the file is opened in a spreadsheet. A test pins it down:
def test_no_formula_injection(client, seed_event): seed_event(actor='=HYPERLINK("http://example.invalid","click")') body = client.get("/audit-log/export.csv").text rows = list(csv.reader(io.StringIO(body)))[1:] # parse properly; skip header for row in rows: for cell in row: assert not cell.startswith(("=", "+", "-", "@")), cell
Day 4, range: borrow a method.
USER STORYAs the data protection officer, I want the export reviewed for privacythreats, so that no role can export data it cannot see on screen.DEFINITION OF READY- The export endpoint, the table definitions and auth/roles.yaml.DEFINITION OF DONE- A LINDDUN privacy threat model (a privacy threat-modelling checklist, the privacy counterpart of STRIDE).- A failing test for each threat found, paying particular attention to columns hidden on screen for some roles.DEFINITION OF SUCCESS- For every role in auth/roles.yaml, a test confirms the exported columns are a subset of the columns that role sees on screen.
It finds that the export includes the ip_address column, which is hidden on screen for support staff. One more test, one more fix.
Day 5, oracle: protect what you built. Move test_export_matches_screen, the injection test and the privacy tests into tests/contracts/, add that path to the hook and to CODEOWNERS (as in Part 6), and have an independent review agent read the final diff.
The log. Five lines, one per day: two export designs measured, one invariant, one injection bug, one privacy leak, four protected checks. The spec-driven version would have shipped both bugs. Write that log up, and it is your next post.
Then tell me how far you got. I would genuinely like to know.