[{"data":1,"prerenderedAt":624},["ShallowReactive",2],{"\u002Fdocs\u002Fsdd":3},{"id":4,"title":5,"body":6,"description":616,"extension":617,"meta":618,"navigation":619,"path":620,"seo":621,"stem":622,"__hash__":623},"docs\u002Fdocs\u002Fsdd.md","Spec-Driven Development",{"type":7,"value":8,"toc":601},"minimark",[9,18,57,60,65,75,79,89,188,206,211,220,281,285,291,310,333,337,349,376,380,397,401,411,445,449,456,509,531,550,554,581,585],[10,11,12,13,17],"p",{},"CAF follows Spec-Driven Development (SDD). The unit of work is a written spec, not a\nchat message. The level CAF aims for is ",[14,15,16],"strong",{},"spec-first, moving toward spec-anchored"," — not\nspec-as-source.",[19,20,21,37,51],"ul",{},[22,23,24,27,28,32,33,36],"li",{},[14,25,26],{},"Spec-first."," The Planner writes ",[29,30,31],"code",{},"requirements.md"," (outcome, scope, decisions,\nacceptance criteria, each with a ",[29,34,35],{},"Verify:"," line) before any code is written.",[22,38,39,42,43,46,47,50],{},[14,40,41],{},"Spec-anchored."," Once approved, the spec stays the reference. Tasks,\nimplementation, validation and review are all checked against its acceptance\ncriteria. An agent never edits an approved spec; a needed change is proposed in\n",[29,44,45],{},"verify-report.md"," under ",[29,48,49],{},"## Proposed Spec Changes"," and a human decides.",[22,52,53,56],{},[14,54,55],{},"Not spec-as-source."," The code stays the source of truth for behavior. The spec is\nnot regenerated into code, and code is not regenerated from the spec.",[10,58,59],{},"Human review of the pull request stays mandatory. There is no auto-merge.",[61,62,64],"h2",{"id":63},"the-flow","The flow",[66,67,72],"pre",{"className":68,"code":70,"language":71},[69],"language-text","ticket or chat\n  → Planner      Specify → Clarify → Plan → Tasks\n  → spec gate    optional, a human approves the spec\n  → implement    caf-frontend \u002F caf-backend, then self-verify\n  → Validator    checks every acceptance criterion\n  → Reviewer     qualitative review against the spec and the diff\n  → pull request\n","text",[29,73,70],{"__ignoreMap":74},"",[61,76,78],{"id":77},"what-the-planner-writes","What the Planner writes",[10,80,81,82,84,85,88],{},"The Planner always writes ",[29,83,31],{}," and ",[29,86,87],{},"tasks.md",", and writes a third file\nwhen the request needs one.",[90,91,92,111],"table",{},[93,94,95],"thead",{},[96,97,98,102,105],"tr",{},[99,100,101],"th",{},"File",[99,103,104],{},"Contents",[99,106,107,110],{},[29,108,109],{},"Status:"," line",[112,113,114,133,160,174],"tbody",{},[96,115,116,121,130],{},[117,118,119],"td",{},[29,120,31],{},[117,122,123,124,127,128,110],{},"Outcome, scope, findings, assumptions, decisions, constraints, open questions, and acceptance criteria numbered ",[29,125,126],{},"AC-n",", each with a ",[29,129,35],{},[117,131,132],{},"Yes",[96,134,135,139,157],{},[117,136,137],{},[29,138,87],{},[117,140,141,142,145,146,84,149,152,153,156],{},"The concrete tasks, split under ",[29,143,144],{},"## Frontend Tasks",", ",[29,147,148],{},"## Backend Tasks",[29,150,151],{},"## Docs Tasks",", ending with ",[29,154,155],{},"## Coverage",": a map from each criterion to the tasks that serve it (not a task itself)",[117,158,159],{},"No",[96,161,162,167,172],{},[117,163,164],{},[29,165,166],{},"design.md",[117,168,169,170],{},"A technical design. Written only when the ticket spans more than one app or service, adds or changes a schema or migration, or adds or changes a contract between layers. None of the three: no ",[29,171,166],{},[117,173,159],{},[96,175,176,181,186],{},[117,177,178],{},[29,179,180],{},"breakdown.md",[117,182,183,184],{},"A proposal to split a request that holds more than one outcome that could ship and be used on its own (item, order, dependencies, acceptance-criteria outline). One outcome reached in many steps is not split; its steps go to ",[29,185,87],{},[117,187,159],{},[10,189,190,84,192,194,195,145,198,201,202,205],{},[29,191,166],{},[29,193,180],{}," have no status of their own: they ride the approval of\nthe spec. The formats live in the skills ",[29,196,197],{},"caf-spec",[29,199,200],{},"caf-design"," and\n",[29,203,204],{},"caf-breakdown",".",[207,208,210],"h3",{"id":209},"the-status-of-a-spec","The status of a spec",[10,212,213,214,216,217,219],{},"The first ",[29,215,109],{}," line of ",[29,218,31],{}," has one of four values:",[90,221,222,232],{},[93,223,224],{},[96,225,226,229],{},[99,227,228],{},"Value",[99,230,231],{},"Meaning",[112,233,234,244,261,271],{},[96,235,236,241],{},[117,237,238],{},[29,239,240],{},"DRAFT",[117,242,243],{},"Written, not approved yet",[96,245,246,251],{},[117,247,248],{},[29,249,250],{},"NEEDS_CLARIFICATION",[117,252,253,254,257,258,260],{},"A question marked ",[29,255,256],{},"BLOCKING"," has no answer; no ",[29,259,87],{}," is written",[96,262,263,268],{},[117,264,265],{},[29,266,267],{},"APPROVED",[117,269,270],{},"A human approved it. Agents no longer edit it",[96,272,273,278],{},[117,274,275],{},[29,276,277],{},"NEEDS_HUMAN",[117,279,280],{},"The run could not go on without a human decision",[207,282,284],{"id":283},"acceptance-criteria-and-their-evidence","Acceptance criteria and their evidence",[10,286,287,288,290],{},"Every acceptance criterion describes one observable behavior and carries a ",[29,289,35],{},"\nline in one of three forms:",[19,292,293,299,304],{},[22,294,295,298],{},[29,296,297],{},"automated test"," — names the test file, or the task that creates it",[22,300,301],{},[29,302,303],{},"command: \u003Ccommand> | expect: \u003Cexit code or output>",[22,305,306,309],{},[29,307,308],{},"manual"," — a human must check it",[10,311,312,313,315,316,145,319,145,322,325,326,328,329,332],{},"An implementation agent then writes one evidence line per criterion in\n",[29,314,45],{},", in one of five forms: ",[29,317,318],{},"automated-test",[29,320,321],{},"command",[29,323,324],{},"build-only",",\n",[29,327,308],{}," or ",[29,330,331],{},"none",". The Validator and the Reviewer judge those lines.",[61,334,336],{"id":335},"clarify-asking-instead-of-guessing","Clarify: asking instead of guessing",[10,338,339,340,343,344,328,346,205],{},"The Planner reads the repo before it asks. A fact it can read is never a question, and\na claim it cannot source is written as ",[29,341,342],{},"Assumption A-n:"," with its basis. What a human\nmust decide becomes a question, tagged ",[29,345,256],{},[29,347,348],{},"NON-BLOCKING",[10,350,351,352,354,355,358,359,361,362,365,366,371,372,375],{},"While a ",[29,353,256],{}," question has no ",[29,356,357],{},"Answer:",", no ",[29,360,87],{}," is written. On a ticket run\nnobody answers in chat, so the Planner writes ",[29,363,364],{},"Status: NEEDS_CLARIFICATION"," and stops.\n",[367,368,370],"a",{"href":369},"\u002Fdocs\u002Fcaf-orchestrator#clarify-and-the-spec-gate","CAF Orchestrator"," then pushes the\ndraft to the branch and posts the questions as a comment on the ticket\n(",[29,373,374],{},"❓ CAF-CLARIFY","). Answer in a comment, trigger the ticket again, and the Planner\ncontinues the same draft.",[61,377,379],{"id":378},"the-spec-gate","The spec gate",[10,381,382,383,386,387,390,391,393,394,396],{},"A ticket carrying the ",[29,384,385],{},"spec-approval"," label (configurable) stops after the Planner with\na Draft PR that holds the spec only. A human reviews it, edits it on the branch if\nneeded, and comments ",[29,388,389],{},"\u002Fcaf-approve-spec",". The Orchestrator changes only the ",[29,392,109],{},"\nline to ",[29,395,267],{}," and continues with implementation. Without the label, the pipeline\nruns straight through after the Planner.",[61,398,400],{"id":399},"an-approved-spec-is-a-contract","An approved spec is a contract",[10,402,403,404,406,407,410],{},"Once ",[29,405,31],{}," says ",[29,408,409],{},"Status: APPROVED",":",[19,412,413,422,434],{},[22,414,415,416,418,419,421],{},"No agent writes to it. The implementation agents never write ",[29,417,31],{}," or\n",[29,420,87],{},"; the Reviewer treats a change to an approved spec as a blocking finding.",[22,423,424,425,427,428,430,431,205],{},"A spec that turns out wrong, ambiguous or impossible is reported in ",[29,426,45],{},"\nunder ",[29,429,49],{},", and the run stops with ",[29,432,433],{},"Status: NEEDS_HUMAN",[22,435,436,437,440,441,444],{},"A review comment that asks to change the goal, scope or a criterion\n(",[29,438,439],{},"\u002Fcaf-fix-review",") is logged as a proposal and marked ",[29,442,443],{},"SKIPPED",", never applied.",[61,446,448],{"id":447},"validator-and-reviewer","Validator and Reviewer",[10,450,451,452,455],{},"The ",[14,453,454],{},"Validator"," gives every acceptance criterion one status by running its evidence\nitself:",[90,457,458,468],{},[93,459,460],{},[96,461,462,465],{},[99,463,464],{},"Status",[99,466,467],{},"When",[112,469,470,484,494],{},[96,471,472,477],{},[117,473,474],{},[29,475,476],{},"PASS",[117,478,479,328,481,483],{},[29,480,318],{},[29,482,321],{}," evidence the Validator ran itself, matching the criterion",[96,485,486,491],{},[117,487,488],{},[29,489,490],{},"FAIL",[117,492,493],{},"It ran the evidence and the result contradicts the criterion",[96,495,496,501],{},[117,497,498],{},[29,499,500],{},"UNVERIFIED",[117,502,503,504,145,506,508],{},"Everything else: ",[29,505,308],{},[29,507,324],{},", no named test, a command it may not run, or no evidence line",[10,510,511,513,514,516,517,520,521,524,525,527,528,530],{},[29,512,500],{}," never makes the report ",[29,515,490],{},", but its count is always on the\n",[29,518,519],{},"Unverified:"," line. In a pipeline run by CAF Orchestrator, a report that says\n",[29,522,523],{},"Status: PASS"," while every criterion is ",[29,526,500],{}," is treated as ",[29,529,277],{},":\nnothing was proven.",[10,532,451,533,536,537,540,541,145,544,328,547,205],{},[14,534,535],{},"Reviewer"," reads evidence and does not run the tests again. It reports scope\ndeviations, tasks not done, criteria that need a human check, and ADR violations, and\nends with a ",[29,538,539],{},"Verdict:"," of ",[29,542,543],{},"APPROVE",[29,545,546],{},"CHANGES REQUESTED",[29,548,549],{},"DEFER",[61,551,553],{"id":552},"language","Language",[10,555,556,557,559,560,145,563,145,565,325,568,145,570,145,573,145,575,84,577,580],{},"The Planner writes the prose of its artifacts in the language of the ticket author,\njudged from the title and the author's own sentences, not from UI text the ticket\nquotes. The words other agents and the Orchestrator read stay fixed in every language:\nsection headings, ",[29,558,109],{}," and its values, ",[29,561,562],{},"AC-n:",[29,564,35],{},[29,566,567],{},"Finding:",[29,569,342],{},[29,571,572],{},"Q-n",[29,574,256],{},[29,576,357],{},[29,578,579],{},"Tidak ada"," (the literal for an\nempty section).",[61,582,584],{"id":583},"what-is-and-is-not-enforced","What is and is not enforced",[10,586,587,588,591,592,594,595,597,598,600],{},"Most of SDD is instructions written into the generated agent definitions and skills.\n",[29,589,590],{},"caf-init"," does not check that an agent followed them. What the Orchestrator does\nenforce in code: stopping on ",[29,593,250],{}," or an unanswered ",[29,596,256],{},"\nquestion, the spec gate and ",[29,599,389],{},", the acceptance-criteria summary on the\nPR, and the validator's command allowlist.",{"title":74,"searchDepth":602,"depth":602,"links":603},2,[604,605,610,611,612,613,614,615],{"id":63,"depth":602,"text":64},{"id":77,"depth":602,"text":78,"children":606},[607,609],{"id":209,"depth":608,"text":210},3,{"id":283,"depth":608,"text":284},{"id":335,"depth":602,"text":336},{"id":378,"depth":602,"text":379},{"id":399,"depth":602,"text":400},{"id":447,"depth":602,"text":448},{"id":552,"depth":602,"text":553},{"id":583,"depth":602,"text":584},"How CAF works from a written spec — the Planner writes it, a human approves it, and every later agent is checked against it.","md",{},true,"\u002Fdocs\u002Fsdd",{"title":5,"description":616},"docs\u002Fsdd","ujlixDY9Z3Ua0n_vmcGaLsU3yA-r8IcYGZGH_OqQjDM",1792519413954]