[{"data":1,"prerenderedAt":1095},["ShallowReactive",2],{"docs-sections":3,"docs-page-\u002Fdocs\u002Fhistory-and-restore":123},[4,9,13,17,22,26,30,34,38,42,46,50,55,59,63,67,72,76,80,85,89,93,97,102,106,110,114,119],{"path":5,"title":6,"description":7,"group":8},"\u002Fdocs","Introduction","What tunables is, the problem it solves, and the principles it holds to.","Get started",{"path":10,"title":11,"description":12,"group":8},"\u002Fdocs\u002Fquickstart","Quickstart","Take one group of settings from constants to a screen with a history, in a Nuxt app on Postgres.",{"path":14,"title":15,"description":16,"group":8},"\u002Fdocs\u002Fpatterns","What it is for","The kinds of value tunables keeps — live limits, plans, per-workspace and per-person values, model choices, values that bound each other, costly switches — and the feature that does each.",{"path":18,"title":19,"description":20,"group":21},"\u002Fdocs\u002Fsettings-and-groups","Settings and groups","Declare each setting once, in a group edited beside what it affects, and read it with types.","Concepts",{"path":23,"title":24,"description":25,"group":21},"\u002Fdocs\u002Fkinds-and-units","Kinds and units","The eight kinds of setting, the built-in units, your own units, and how values are checked and read.",{"path":27,"title":28,"description":29,"group":21},"\u002Fdocs\u002Fchecks-and-guards","Checks and guards","Rules across settings, guards for what your app keeps, within for presets, confirmations for costly changes, and notes.",{"path":31,"title":32,"description":33,"group":21},"\u002Fdocs\u002Fhistory-and-restore","History and restore","Every change is a revision with who, when, why and each value before and after; restoring one runs the same checks as any save.",{"path":35,"title":36,"description":37,"group":21},"\u002Fdocs\u002Fpresets","Presets","Named, reusable configurations with one default per slot, assigned by reference and bounded by the settings.",{"path":39,"title":40,"description":41,"group":21},"\u002Fdocs\u002Fscopes","Scopes","Values per workspace and per person, through layers — the system, a plan, the workspace, the person — each bounded by what it inherits.",{"path":43,"title":44,"description":45,"group":21},"\u002Fdocs\u002Fcatalogs","Catalogs","Lists of allowed choices, such as permitted models, whose entries are retired rather than deleted and cannot be retired while in use.",{"path":47,"title":48,"description":49,"group":21},"\u002Fdocs\u002Fdeployment-values","Deployment values","Values a deployment sets in its environment and nobody tunes while the app runs, declared once and listed in .env.example.",{"path":51,"title":52,"description":53,"group":54},"\u002Fdocs\u002Fstorage","Storage","Postgres through your own client, the four tables and how to create them, joining your transactions, and the storage contract behind it.","Integrate",{"path":56,"title":57,"description":58,"group":54},"\u002Fdocs\u002Fserver","Server and access","Mount tunables' API as a fetch handler in Nitro, Hono, Bun or Deno, as Express middleware or as an oRPC router, with access decided by your app.",{"path":60,"title":61,"description":62,"group":54},"\u002Fdocs\u002Faccess","Who can do what","End users bound by values they never see, staff who tune groups, owners and members who change only their own scope, and the terminal.",{"path":64,"title":65,"description":66,"group":54},"\u002Fdocs\u002Ftesting","Testing","Your app's tunables in memory for its own tests, with values set where a test needs them, and how to test rules, guards and confirmations.",{"path":68,"title":69,"description":70,"group":71},"\u002Fdocs\u002Fnuxt-layer","The Nuxt layer","Ready screens for a Nuxt UI app — a group's form, All settings, history, presets, assignments and catalogs — placed beside what they affect.","Screens",{"path":73,"title":74,"description":75,"group":71},"\u002Fdocs\u002Fvue-composables","Vue composables","Headless composables for building tunables' screens in any Vue app, on any design system.",{"path":77,"title":78,"description":79,"group":71},"\u002Fdocs\u002Ftheming","Theming","The screens bring no colors, fonts or CSS of their own; they take your Nuxt UI theme.",{"path":81,"title":82,"description":83,"group":84},"\u002Fdocs\u002Fcli","The CLI","The tunables command, tunables.config.ts, and which commands need a database.","CLI",{"path":86,"title":87,"description":88,"group":84},"\u002Fdocs\u002Fcli-check","Check and generate","The commands that need no database — checking definitions, writing .env.example, and keeping explanations and defaults in step with a pdd-kit Product Model.",{"path":90,"title":91,"description":92,"group":84},"\u002Fdocs\u002Fcli-values","Read and change values","The commands that read and change stored values, through the same checks and history as the screens.",{"path":94,"title":95,"description":96,"group":84},"\u002Fdocs\u002Fcli-skills","Install skills","Install tunables' agent skills for Claude Code, Codex CLI, Cursor, Gemini CLI and GitHub Copilot, and keep them current.",{"path":98,"title":99,"description":100,"group":101},"\u002Fdocs\u002Fskills","Agent skills","Three skills that let a coding agent adopt tunables, define settings the right way and verify that every value has one home.","Skills",{"path":103,"title":104,"description":105,"group":101},"\u002Fdocs\u002Fskill-adopt","tunables-adopt","Bring tunables into an app that has none yet, from an inventory of every value to a wired, synced app with the old homes removed.",{"path":107,"title":108,"description":109,"group":101},"\u002Fdocs\u002Fskill-define","tunables-define","Add, change, rename or remove one value in an app that uses tunables, with its home, its checks, its reads and what happens to stored values.",{"path":111,"title":112,"description":113,"group":101},"\u002Fdocs\u002Fskill-verify","tunables-verify","Audit an app's tunables against their rules, report every finding with where it is and the rule it breaks, and fix only the findings you choose.",{"path":115,"title":116,"description":117,"group":118},"\u002Fdocs\u002Fapi","API reference","Every export of the tunables package, by the subpath it is imported from.","Reference",{"path":120,"title":121,"description":122,"group":118},"\u002Fdocs\u002Ftasklane-example","Tasklane, the example app","A todo app with workspaces and people as tunables — two groups, plans as a layer, a catalog of models, scopes, a rule, a confirmation, and the playground that runs it.",{"id":124,"title":32,"body":125,"description":33,"extension":1090,"group":21,"meta":1091,"navigation":510,"order":354,"path":31,"seo":1092,"stem":1093,"__hash__":1094},"docs\u002Fdocs\u002Fhistory-and-restore.md",{"type":126,"value":127,"toc":1082},"minimark",[128,132,150,155,384,409,447,451,753,771,775,794,854,870,873,904,908,921,966,975,1040,1044,1064,1068,1078],[129,130,32],"h1",{"id":131},"history-and-restore",[133,134,135,136,140,141,145,146,149],"p",{},"Every change tunables stores is recorded as a ",[137,138,139],"strong",{},"revision",", in the same\ntransaction as the change itself. Nothing changes a setting without leaving\none: not a save from a screen, not ",[142,143,144],"code",{},"tunables set",", not ",[142,147,148],{},"sync",", not a reset or\na restore.",[151,152,154],"h2",{"id":153},"a-revision","A revision",[156,157,162],"pre",{"className":158,"code":159,"language":160,"meta":161,"style":161},"language-ts shiki shiki-themes tunables-panel-light tunables-panel-light tunables-panel-dark","interface Revision {\n  id: string \u002F\u002F increasing: a later revision has a larger id\n  target: { kind: 'group' | 'preset' | 'catalog' | 'assignment', name: string, id?: string }\n  actor: string | null \u002F\u002F who, as their name\n  reason: string | null \u002F\u002F why\n  changes: { key: string, from: unknown, to: unknown }[] \u002F\u002F each value before and after\n  snapshot: unknown \u002F\u002F the whole target after the change, so it can be restored\n  at: string \u002F\u002F when, as an ISO timestamp\n}\n","ts","",[142,163,164,181,198,275,293,310,352,365,378],{"__ignoreMap":161},[165,166,169,173,177],"span",{"class":167,"line":168},"line",1,[165,170,172],{"class":171},"sZ4mS","interface",[165,174,176],{"class":175},"sOThN"," Revision",[165,178,180],{"class":179},"sp9ci"," {\n",[165,182,184,188,191,194],{"class":167,"line":183},2,[165,185,187],{"class":186},"sVz71","  id",[165,189,190],{"class":179},":",[165,192,193],{"class":175}," string",[165,195,197],{"class":196},"sKllz"," \u002F\u002F increasing: a later revision has a larger id\n",[165,199,201,204,206,209,212,214,217,221,224,227,229,232,234,236,238,241,243,245,247,250,252,255,258,260,262,264,267,270,272],{"class":167,"line":200},3,[165,202,203],{"class":186},"  target",[165,205,190],{"class":179},[165,207,208],{"class":179}," {",[165,210,211],{"class":186}," kind",[165,213,190],{"class":179},[165,215,216],{"class":179}," '",[165,218,220],{"class":219},"sjCzm","group",[165,222,223],{"class":179},"'",[165,225,226],{"class":179}," |",[165,228,216],{"class":179},[165,230,231],{"class":219},"preset",[165,233,223],{"class":179},[165,235,226],{"class":179},[165,237,216],{"class":179},[165,239,240],{"class":219},"catalog",[165,242,223],{"class":179},[165,244,226],{"class":179},[165,246,216],{"class":179},[165,248,249],{"class":219},"assignment",[165,251,223],{"class":179},[165,253,254],{"class":179},",",[165,256,257],{"class":186}," name",[165,259,190],{"class":179},[165,261,193],{"class":175},[165,263,254],{"class":179},[165,265,266],{"class":186}," id",[165,268,269],{"class":179},"?:",[165,271,193],{"class":175},[165,273,274],{"class":179}," }\n",[165,276,278,281,283,285,287,290],{"class":167,"line":277},4,[165,279,280],{"class":186},"  actor",[165,282,190],{"class":179},[165,284,193],{"class":175},[165,286,226],{"class":179},[165,288,289],{"class":175}," null",[165,291,292],{"class":196}," \u002F\u002F who, as their name\n",[165,294,296,299,301,303,305,307],{"class":167,"line":295},5,[165,297,298],{"class":186},"  reason",[165,300,190],{"class":179},[165,302,193],{"class":175},[165,304,226],{"class":179},[165,306,289],{"class":175},[165,308,309],{"class":196}," \u002F\u002F why\n",[165,311,313,316,318,320,323,325,327,329,332,334,337,339,342,344,346,349],{"class":167,"line":312},6,[165,314,315],{"class":186},"  changes",[165,317,190],{"class":179},[165,319,208],{"class":179},[165,321,322],{"class":186}," key",[165,324,190],{"class":179},[165,326,193],{"class":175},[165,328,254],{"class":179},[165,330,331],{"class":186}," from",[165,333,190],{"class":179},[165,335,336],{"class":175}," unknown",[165,338,254],{"class":179},[165,340,341],{"class":186}," to",[165,343,190],{"class":179},[165,345,336],{"class":175},[165,347,348],{"class":179}," }[]",[165,350,351],{"class":196}," \u002F\u002F each value before and after\n",[165,353,355,358,360,362],{"class":167,"line":354},7,[165,356,357],{"class":186},"  snapshot",[165,359,190],{"class":179},[165,361,336],{"class":175},[165,363,364],{"class":196}," \u002F\u002F the whole target after the change, so it can be restored\n",[165,366,368,371,373,375],{"class":167,"line":367},8,[165,369,370],{"class":186},"  at",[165,372,190],{"class":179},[165,374,193],{"class":175},[165,376,377],{"class":196}," \u002F\u002F when, as an ISO timestamp\n",[165,379,381],{"class":167,"line":380},9,[165,382,383],{"class":179},"}\n",[133,385,386,387,390,391,396,397,400,401,404,405,408],{},"A revision's ",[142,388,389],{},"target"," names what changed: a group by its id, with the\n",[392,393,395],"a",{"href":394},".\u002Fscopes","scope"," key as ",[142,398,399],{},"id"," when the change was made at a scope, such as\n",[142,402,403],{},"{ kind: 'group', name: 'limits', id: 'workspace=acme' }","; a preset by its set\nand key; a catalog entry by its catalog and id; an assignment by its preset\nset and subject. ",[142,406,407],{},"changes"," lists only the fields that differ.",[133,410,411,412,415,416,421,422,425,426,428,429,432,433,436,437,428,441,428,444],{},"The ",[142,413,414],{},"actor"," is whoever the change was made by: on the screens, the person your\n",[392,417,419],{"href":418},".\u002Fserver#access",[142,420,414],{}," function returns; from a terminal,\n",[142,423,424],{},"\u003Cyour username> (terminal)","; from ",[142,427,148],{},", ",[142,430,431],{},"tunables sync"," unless you name\nsomeone. The ",[142,434,435],{},"reason"," is what the person wrote, or what tunables says it did:\n",[438,439,440],"em",{},"\"Seeded with the defaults.\"",[438,442,443],{},"\"Reset to defaults.\"",[438,445,446],{},"\"Restored revision 9.\"",[151,448,450],{"id":449},"reading-the-history","Reading the history",[156,452,454],{"className":158,"code":453,"language":160,"meta":161,"style":161},"const revisions = await tunables.history('limits', { limit: 20 })\n\n\u002F\u002F The page before the oldest one shown\nconst older = await tunables.history('limits', { limit: 20, before: revisions.at(-1)?.id })\n\n\u002F\u002F A scope's own history\nawait tunables.history({ kind: 'group', name: 'limits', id: 'workspace=acme' })\n\n\u002F\u002F A preset's or a catalog entry's history\nawait tunables.history({ kind: 'preset', name: 'plans', id: 'pro' })\nawait tunables.history({ kind: 'catalog', name: 'models', id: 'small' })\n",[142,455,456,506,512,517,582,586,591,642,646,651,702],{"__ignoreMap":161},[165,457,458,461,464,467,470,474,478,481,484,486,489,491,493,495,498,500,503],{"class":167,"line":168},[165,459,460],{"class":171},"const",[165,462,463],{"class":186}," revisions ",[165,465,466],{"class":179},"=",[165,468,469],{"class":171}," await",[165,471,473],{"class":472},"sq0K3"," tunables",[165,475,477],{"class":476},"sBd0f",".",[165,479,480],{"class":175},"history",[165,482,483],{"class":179},"(",[165,485,223],{"class":179},[165,487,488],{"class":219},"limits",[165,490,223],{"class":179},[165,492,254],{"class":179},[165,494,208],{"class":179},[165,496,497],{"class":186}," limit",[165,499,190],{"class":179},[165,501,502],{"class":219}," 20",[165,504,505],{"class":179}," })\n",[165,507,508],{"class":167,"line":183},[165,509,511],{"emptyLinePlaceholder":510},true,"\n",[165,513,514],{"class":167,"line":200},[165,515,516],{"class":196},"\u002F\u002F The page before the oldest one shown\n",[165,518,519,521,524,526,528,530,532,534,536,538,540,542,544,546,548,550,552,554,557,559,562,564,567,570,573,576,579],{"class":167,"line":277},[165,520,460],{"class":171},[165,522,523],{"class":186}," older ",[165,525,466],{"class":179},[165,527,469],{"class":171},[165,529,473],{"class":472},[165,531,477],{"class":476},[165,533,480],{"class":175},[165,535,483],{"class":179},[165,537,223],{"class":179},[165,539,488],{"class":219},[165,541,223],{"class":179},[165,543,254],{"class":179},[165,545,208],{"class":179},[165,547,497],{"class":186},[165,549,190],{"class":179},[165,551,502],{"class":219},[165,553,254],{"class":179},[165,555,556],{"class":186}," before",[165,558,190],{"class":179},[165,560,561],{"class":472}," revisions",[165,563,477],{"class":476},[165,565,566],{"class":175},"at",[165,568,569],{"class":179},"(-",[165,571,572],{"class":219},"1",[165,574,575],{"class":179},")?.",[165,577,578],{"class":186},"id ",[165,580,581],{"class":179},"})\n",[165,583,584],{"class":167,"line":295},[165,585,511],{"emptyLinePlaceholder":510},[165,587,588],{"class":167,"line":312},[165,589,590],{"class":196},"\u002F\u002F A scope's own history\n",[165,592,593,596,598,600,602,605,607,609,611,613,615,617,619,621,623,625,627,629,631,633,635,638,640],{"class":167,"line":354},[165,594,595],{"class":171},"await",[165,597,473],{"class":472},[165,599,477],{"class":476},[165,601,480],{"class":175},[165,603,604],{"class":179},"({",[165,606,211],{"class":186},[165,608,190],{"class":179},[165,610,216],{"class":179},[165,612,220],{"class":219},[165,614,223],{"class":179},[165,616,254],{"class":179},[165,618,257],{"class":186},[165,620,190],{"class":179},[165,622,216],{"class":179},[165,624,488],{"class":219},[165,626,223],{"class":179},[165,628,254],{"class":179},[165,630,266],{"class":186},[165,632,190],{"class":179},[165,634,216],{"class":179},[165,636,637],{"class":219},"workspace=acme",[165,639,223],{"class":179},[165,641,505],{"class":179},[165,643,644],{"class":167,"line":367},[165,645,511],{"emptyLinePlaceholder":510},[165,647,648],{"class":167,"line":380},[165,649,650],{"class":196},"\u002F\u002F A preset's or a catalog entry's history\n",[165,652,654,656,658,660,662,664,666,668,670,672,674,676,678,680,682,685,687,689,691,693,695,698,700],{"class":167,"line":653},10,[165,655,595],{"class":171},[165,657,473],{"class":472},[165,659,477],{"class":476},[165,661,480],{"class":175},[165,663,604],{"class":179},[165,665,211],{"class":186},[165,667,190],{"class":179},[165,669,216],{"class":179},[165,671,231],{"class":219},[165,673,223],{"class":179},[165,675,254],{"class":179},[165,677,257],{"class":186},[165,679,190],{"class":179},[165,681,216],{"class":179},[165,683,684],{"class":219},"plans",[165,686,223],{"class":179},[165,688,254],{"class":179},[165,690,266],{"class":186},[165,692,190],{"class":179},[165,694,216],{"class":179},[165,696,697],{"class":219},"pro",[165,699,223],{"class":179},[165,701,505],{"class":179},[165,703,705,707,709,711,713,715,717,719,721,723,725,727,729,731,733,736,738,740,742,744,746,749,751],{"class":167,"line":704},11,[165,706,595],{"class":171},[165,708,473],{"class":472},[165,710,477],{"class":476},[165,712,480],{"class":175},[165,714,604],{"class":179},[165,716,211],{"class":186},[165,718,190],{"class":179},[165,720,216],{"class":179},[165,722,240],{"class":219},[165,724,223],{"class":179},[165,726,254],{"class":179},[165,728,257],{"class":186},[165,730,190],{"class":179},[165,732,216],{"class":179},[165,734,735],{"class":219},"models",[165,737,223],{"class":179},[165,739,254],{"class":179},[165,741,266],{"class":186},[165,743,190],{"class":179},[165,745,216],{"class":179},[165,747,748],{"class":219},"small",[165,750,223],{"class":179},[165,752,505],{"class":179},[133,754,755,756,759,760,762,763,766,767,770],{},"Revisions come newest first, 50 at a time unless you ask for a ",[142,757,758],{},"limit"," (at\nmost 500). A group's history without an ",[142,761,399],{}," is its system values' history.\nThe group form lists its group's history, or its scope's; ",[142,764,765],{},"TunablesHistory","\nshows any target's, and ",[142,768,769],{},"tunables history \u003Cgroup> [--scope …]"," prints it at a\nterminal.",[151,772,774],{"id":773},"restoring","Restoring",[133,776,777,778,782,783,428,786,789,790,793],{},"Restoring puts a group back as it was after an earlier revision. It is a save\nlike any other: the revision's snapshot goes through every\n",[392,779,781],{"href":780},".\u002Fchecks-and-guards","check",", including ",[142,784,785],{},"rules",[142,787,788],{},"within",", your guards and\n",[142,791,792],{},"confirm",". If the settings, the presets or your records have moved on since,\nand the old values would break something, the restore is refused and says why.",[156,795,797],{"className":158,"code":796,"language":160,"meta":161,"style":161},"const outcome = await tunables.restore('9', { actor, reason: 'The promotion is over.' })\n\u002F\u002F outcome.revision.reason: \"Restored revision 9. The promotion is over.\"\n",[142,798,799,849],{"__ignoreMap":161},[165,800,801,803,806,808,810,812,814,817,819,821,824,826,828,830,833,835,838,840,842,845,847],{"class":167,"line":168},[165,802,460],{"class":171},[165,804,805],{"class":186}," outcome ",[165,807,466],{"class":179},[165,809,469],{"class":171},[165,811,473],{"class":472},[165,813,477],{"class":476},[165,815,816],{"class":175},"restore",[165,818,483],{"class":179},[165,820,223],{"class":179},[165,822,823],{"class":219},"9",[165,825,223],{"class":179},[165,827,254],{"class":179},[165,829,208],{"class":179},[165,831,832],{"class":186}," actor",[165,834,254],{"class":179},[165,836,837],{"class":186}," reason",[165,839,190],{"class":179},[165,841,216],{"class":179},[165,843,844],{"class":219},"The promotion is over.",[165,846,223],{"class":179},[165,848,505],{"class":179},[165,850,851],{"class":167,"line":183},[165,852,853],{"class":196},"\u002F\u002F outcome.revision.reason: \"Restored revision 9. The promotion is over.\"\n",[855,856,857,861,864,867],"ul",{},[858,859,860],"li",{},"A restore records a new revision; it never rewrites or removes history.",[858,862,863],{},"Fields declared since the revision was made take their defaults.",[858,865,866],{},"A scope's revision puts back that scope's own values exactly: what it set\nthen, it sets again; what it did not set, it inherits again.",[858,868,869],{},"Only group revisions are restored. Presets and catalog entries change\nthrough their own operations, each recorded the same way.",[133,871,872],{},"From a terminal:",[156,874,878],{"className":875,"code":876,"language":877,"meta":161,"style":161},"language-bash shiki shiki-themes tunables-panel-light tunables-panel-light tunables-panel-dark","npx tunables restore 9 --reason \"The promotion is over.\"\n","bash",[142,879,880],{"__ignoreMap":161},[165,881,882,885,887,890,893,896,899,901],{"class":167,"line":168},[165,883,884],{"class":175},"npx",[165,886,473],{"class":219},[165,888,889],{"class":219}," restore",[165,891,892],{"class":219}," 9",[165,894,895],{"class":219}," --reason",[165,897,898],{"class":179}," \"",[165,900,844],{"class":219},[165,902,903],{"class":179},"\"\n",[151,905,907],{"id":906},"resetting-to-defaults","Resetting to defaults",[133,909,910,913,914,917,918,920],{},[142,911,912],{},"reset"," is a save of the defaults the definitions declare, for some fields or\nall of them, and is recorded with ",[438,915,916],{},"\"Reset maxProjects to default.\""," or\n",[438,919,443],{}," unless you give a reason. The group form offers it per\nfield.",[156,922,924],{"className":158,"code":923,"language":160,"meta":161,"style":161},"await tunables.reset('limits', ['maxProjects'], { actor })\n",[142,925,926],{"__ignoreMap":161},[165,927,928,930,932,934,936,938,940,942,944,946,949,951,954,956,959,961,964],{"class":167,"line":168},[165,929,595],{"class":171},[165,931,473],{"class":472},[165,933,477],{"class":476},[165,935,912],{"class":175},[165,937,483],{"class":179},[165,939,223],{"class":179},[165,941,488],{"class":219},[165,943,223],{"class":179},[165,945,254],{"class":179},[165,947,948],{"class":179}," [",[165,950,223],{"class":179},[165,952,953],{"class":219},"maxProjects",[165,955,223],{"class":179},[165,957,958],{"class":179},"],",[165,960,208],{"class":179},[165,962,963],{"class":186}," actor ",[165,965,581],{"class":179},[133,967,968,969,971,972,190],{},"At a scope, ",[142,970,912],{}," stops overriding instead, and is recorded with ",[438,973,974],{},"\"Use the\ninherited maxProjects.\"",[156,976,978],{"className":158,"code":977,"language":160,"meta":161,"style":161},"await tunables.reset('limits', ['maxProjects'], { actor, scope: { workspace: 'acme' } })\n",[142,979,980],{"__ignoreMap":161},[165,981,982,984,986,988,990,992,994,996,998,1000,1002,1004,1006,1008,1010,1012,1014,1016,1019,1021,1023,1026,1028,1030,1033,1035,1038],{"class":167,"line":168},[165,983,595],{"class":171},[165,985,473],{"class":472},[165,987,477],{"class":476},[165,989,912],{"class":175},[165,991,483],{"class":179},[165,993,223],{"class":179},[165,995,488],{"class":219},[165,997,223],{"class":179},[165,999,254],{"class":179},[165,1001,948],{"class":179},[165,1003,223],{"class":179},[165,1005,953],{"class":219},[165,1007,223],{"class":179},[165,1009,958],{"class":179},[165,1011,208],{"class":179},[165,1013,832],{"class":186},[165,1015,254],{"class":179},[165,1017,1018],{"class":186}," scope",[165,1020,190],{"class":179},[165,1022,208],{"class":179},[165,1024,1025],{"class":186}," workspace",[165,1027,190],{"class":179},[165,1029,216],{"class":179},[165,1031,1032],{"class":219},"acme",[165,1034,223],{"class":179},[165,1036,1037],{"class":179}," }",[165,1039,505],{"class":179},[151,1041,1043],{"id":1042},"who-may-read-it","Who may read it",[133,1045,1046,1047,1050,1051,1054,1055,1060,1061,477],{},"Reading history is a ",[142,1048,1049],{},"read"," of its target; restoring is a ",[142,1052,1053],{},"change"," of the\ngroup. For a scope's revisions, the request carries the scope, so an owner can\nbe allowed their workspace's history and nothing else. Your\n",[392,1056,1057],{"href":418},[142,1058,1059],{},"authorize"," decides both, like every other request; see\n",[392,1062,61],{"href":1063},".\u002Faccess",[151,1065,1067],{"id":1066},"where-it-is-stored","Where it is stored",[133,1069,1070,1071,1074,1075,477],{},"Revisions are rows in ",[142,1072,1073],{},"tunables_revisions",", appended and never updated. See\n",[392,1076,52],{"href":1077},".\u002Fstorage#the-tables",[1079,1080,1081],"style",{},"html pre.shiki code .sZ4mS, html code.shiki .sZ4mS{--shiki-light:#115E59;--shiki-default:#115E59;--shiki-dark:#5EEAD4}html pre.shiki code .sOThN, html code.shiki .sOThN{--shiki-light:#2A3439;--shiki-light-font-weight:bold;--shiki-default:#2A3439;--shiki-default-font-weight:bold;--shiki-dark:#F6F8F8;--shiki-dark-font-weight:bold}html pre.shiki code .sp9ci, html code.shiki .sp9ci{--shiki-light:#4F5D63;--shiki-default:#4F5D63;--shiki-dark:#A3AFB4}html pre.shiki code .sVz71, html code.shiki .sVz71{--shiki-light:#182025;--shiki-default:#182025;--shiki-dark:#E6EBEC}html pre.shiki code .sKllz, html code.shiki .sKllz{--shiki-light:#4F5D63;--shiki-light-font-style:italic;--shiki-default:#4F5D63;--shiki-default-font-style:italic;--shiki-dark:#A3AFB4;--shiki-dark-font-style:italic}html pre.shiki code .sjCzm, html code.shiki .sjCzm{--shiki-light:#92400E;--shiki-default:#92400E;--shiki-dark:#FCD34D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sq0K3, html code.shiki .sq0K3{--shiki-light:#182025;--shiki-light-font-weight:bold;--shiki-default:#182025;--shiki-default-font-weight:bold;--shiki-dark:#E6EBEC;--shiki-dark-font-weight:bold}html pre.shiki code .sBd0f, html code.shiki .sBd0f{--shiki-light:#4F5D63;--shiki-light-font-weight:bold;--shiki-default:#4F5D63;--shiki-default-font-weight:bold;--shiki-dark:#A3AFB4;--shiki-dark-font-weight:bold}",{"title":161,"searchDepth":183,"depth":183,"links":1083},[1084,1085,1086,1087,1088,1089],{"id":153,"depth":183,"text":154},{"id":449,"depth":183,"text":450},{"id":773,"depth":183,"text":774},{"id":906,"depth":183,"text":907},{"id":1042,"depth":183,"text":1043},{"id":1066,"depth":183,"text":1067},"md",{},{"title":32,"description":33},"docs\u002Fhistory-and-restore","GG-xizkaENDQqLB-qtay24d39B8I51dmtn69tCxqjpA",1792845117975]