[{"data":1,"prerenderedAt":916},["ShallowReactive",2],{"cycle-doc-design-c121-plan\u002F00-model.md":3},{"cycle":4,"project":7,"path":10,"title":11,"toc":12,"ast":17},{"id":5,"title":6},"c121","Governance v1 Scope",{"id":8,"label":9},"design","Design","plan\u002F00-model.md","00 · Model (Wave 1)",[13,14,15,16],"Today","Steps","Done when","Look for (review)",{"type":18,"children":19},"root",[20,34,91,97,262,267,847,852,900,905],{"type":21,"tag":22,"props":23,"children":24},"element","p",{},[25,32],{"type":21,"tag":26,"props":27,"children":28},"strong",{},[29],{"type":30,"value":31},"text","TL;DR:",{"type":30,"value":33}," the shared world learns the v1 rules: reasons on loosening and revoking, mode + Until instead of snooze, one shared draft behind local staging, per-endpoint fleet, JSON of a version, findings that carry their config version and say whether a person or a re-evaluation moved them. No surface changes beyond keeping today's pages compiling.",{"type":21,"tag":22,"props":35,"children":36},{},[37,42,44,51,53,59,60,66,67,73,75,81,83,89],{"type":21,"tag":26,"props":38,"children":39},{},[40],{"type":30,"value":41},"Owns:",{"type":30,"value":43}," ",{"type":21,"tag":45,"props":46,"children":48},"code",{"className":47},[],[49],{"type":30,"value":50},"app\u002Fdata\u002Fgovernance-fixture.ts",{"type":30,"value":52},", ",{"type":21,"tag":45,"props":54,"children":56},{"className":55},[],[57],{"type":30,"value":58},"app\u002Fcomposables\u002FuseGovernanceMock.ts",{"type":30,"value":52},{"type":21,"tag":45,"props":61,"children":63},{"className":62},[],[64],{"type":30,"value":65},"app\u002Fcomponents\u002Fgovernance\u002Fmock\u002FBar.vue",{"type":30,"value":52},{"type":21,"tag":45,"props":68,"children":70},{"className":69},[],[71],{"type":30,"value":72},"app\u002Fdata\u002Fgovernance-finding-rows.ts",{"type":30,"value":74},". Imports the ",{"type":21,"tag":45,"props":76,"children":78},{"className":77},[],[79],{"type":30,"value":80},"Impact",{"type":30,"value":82}," type from ",{"type":21,"tag":45,"props":84,"children":86},{"className":85},[],[87],{"type":30,"value":88},"app\u002Fdata\u002Fgovernance-impact.ts",{"type":30,"value":90}," (01 writes it; if it isn't there yet, write the interface from README §4 into that file verbatim and tell 01).",{"type":21,"tag":92,"props":93,"children":95},"h2",{"id":94},"today",[96],{"type":30,"value":13},{"type":21,"tag":98,"props":99,"children":100},"ul",{},[101,129,150,161,249],{"type":21,"tag":102,"props":103,"children":104},"li",{},[105,111,113,119,121,127],{"type":21,"tag":45,"props":106,"children":108},{"className":107},[],[109],{"type":30,"value":110},"Exception",{"type":30,"value":112}," (fixture l.169–185) has ",{"type":21,"tag":45,"props":114,"children":116},{"className":115},[],[117],{"type":30,"value":118},"revokedAt",{"type":30,"value":120}," only; ",{"type":21,"tag":45,"props":122,"children":124},{"className":123},[],[125],{"type":30,"value":126},"applyChange",{"type":30,"value":128}," 'exception-revoke' l.968–971.",{"type":21,"tag":102,"props":130,"children":131},{},[132,134,140,142,148],{"type":30,"value":133},"Snooze: change kinds ",{"type":21,"tag":45,"props":135,"children":137},{"className":136},[],[138],{"type":30,"value":139},"policy-snooze",{"type":30,"value":141}," \u002F ",{"type":21,"tag":45,"props":143,"children":145},{"className":144},[],[146],{"type":30,"value":147},"snooze-clear",{"type":30,"value":149},"; applicability turns Enforce→Observe while snoozed (l.786–787).",{"type":21,"tag":102,"props":151,"children":152},{},[153,159],{"type":21,"tag":45,"props":154,"children":156},{"className":155},[],[157],{"type":30,"value":158},"previewChange()",{"type":30,"value":160}," l.1506–1548 returns counts (reachedBefore\u002FAfter, resolves, reopens, enforces, conflicted, openInScope).",{"type":21,"tag":102,"props":162,"children":163},{},[164,166,172,174,180,181,187,188,194,195,201,202,208,210,216,217,223,225,231,233,239,241,247],{"type":30,"value":165},"Publishing state in ",{"type":21,"tag":45,"props":167,"children":169},{"className":168},[],[170],{"type":30,"value":171},"useGovernanceMock.ts",{"type":30,"value":173}," l.84–129: ",{"type":21,"tag":45,"props":175,"children":177},{"className":176},[],[178],{"type":30,"value":179},"edits",{"type":30,"value":52},{"type":21,"tag":45,"props":182,"children":184},{"className":183},[],[185],{"type":30,"value":186},"ops",{"type":30,"value":52},{"type":21,"tag":45,"props":189,"children":191},{"className":190},[],[192],{"type":30,"value":193},"versions",{"type":30,"value":52},{"type":21,"tag":45,"props":196,"children":198},{"className":197},[],[199],{"type":30,"value":200},"pointer",{"type":30,"value":52},{"type":21,"tag":45,"props":203,"children":205},{"className":204},[],[206],{"type":30,"value":207},"drafts",{"type":30,"value":209}," (D-6, D-7), ",{"type":21,"tag":45,"props":211,"children":213},{"className":212},[],[214],{"type":30,"value":215},"log",{"type":30,"value":52},{"type":21,"tag":45,"props":218,"children":220},{"className":219},[],[221],{"type":30,"value":222},"fleet: Record\u003Cversion,count>",{"type":30,"value":224}," (FLEET=100), ",{"type":21,"tag":45,"props":226,"children":228},{"className":227},[],[229],{"type":30,"value":230},"requireApproval",{"type":30,"value":232},"; verbs ",{"type":21,"tag":45,"props":234,"children":236},{"className":235},[],[237],{"type":30,"value":238},"submit\u002Fapprove\u002FdiscardDraft\u002Fpromote\u002Frollback\u002FsetRequireApproval\u002Fpropagate",{"type":30,"value":240}," (l.257–293). ",{"type":21,"tag":45,"props":242,"children":244},{"className":243},[],[245],{"type":30,"value":246},"stageEdit",{"type":30,"value":248}," l.160–170 keeps one line per setting.",{"type":21,"tag":102,"props":250,"children":251},{},[252,254,260],{"type":30,"value":253},"Per-finding ",{"type":21,"tag":45,"props":255,"children":257},{"className":256},[],[258],{"type":30,"value":259},"policyVersion",{"type":30,"value":261}," (\"policy v{n}\").",{"type":21,"tag":92,"props":263,"children":265},{"id":264},"steps",[266],{"type":30,"value":14},{"type":21,"tag":268,"props":269,"children":270},"ol",{},[271,341,426,499,634,715,755,808],{"type":21,"tag":102,"props":272,"children":273},{},[274,279,280,286,288,294,296,301,303,309,311,317,319,325,326,332,334,339],{"type":21,"tag":26,"props":275,"children":276},{},[277],{"type":30,"value":278},"Reasons (D1).",{"type":30,"value":43},{"type":21,"tag":45,"props":281,"children":283},{"className":282},[],[284],{"type":30,"value":285},"MODE_RANK",{"type":30,"value":287}," already exists. Add ",{"type":21,"tag":45,"props":289,"children":291},{"className":290},[],[292],{"type":30,"value":293},"loosens(change, world)",{"type":30,"value":295}," (mode goes down for anyone in scope, incl. exception add with a lower mode, exception revoke that lowers someone, policy mode down). ",{"type":21,"tag":45,"props":297,"children":299},{"className":298},[],[300],{"type":30,"value":246},{"type":30,"value":302}," stores ",{"type":21,"tag":45,"props":304,"children":306},{"className":305},[],[307],{"type":30,"value":308},"{ reason, loosens }",{"type":30,"value":310},"; a loosening edit without a non-empty reason is refused (return ",{"type":21,"tag":45,"props":312,"children":314},{"className":313},[],[315],{"type":30,"value":316},"{ ok:false, why:'reason' }",{"type":30,"value":318}," so the UI can show it). Revoke: ",{"type":21,"tag":45,"props":320,"children":322},{"className":321},[],[323],{"type":30,"value":324},"Exception.revokedBy",{"type":30,"value":52},{"type":21,"tag":45,"props":327,"children":329},{"className":328},[],[330],{"type":30,"value":331},"revokeNote",{"type":30,"value":333}," (required, D1), set in ",{"type":21,"tag":45,"props":335,"children":337},{"className":336},[],[338],{"type":30,"value":126},{"type":30,"value":340},".",{"type":21,"tag":102,"props":342,"children":343},{},[344,349,350,356,357,363,365,371,373,379,381,387,389,395,397,402,403,408,410,416,418,424],{"type":21,"tag":26,"props":345,"children":346},{},[347],{"type":30,"value":348},"Mode + Until (D6).",{"type":30,"value":43},{"type":21,"tag":45,"props":351,"children":353},{"className":352},[],[354],{"type":30,"value":355},"Policy.until?",{"type":30,"value":52},{"type":21,"tag":45,"props":358,"children":360},{"className":359},[],[361],{"type":30,"value":362},"Policy.revertTo?",{"type":30,"value":364},"; ",{"type":21,"tag":45,"props":366,"children":368},{"className":367},[],[369],{"type":30,"value":370},"mode-set",{"type":30,"value":372}," takes ",{"type":21,"tag":45,"props":374,"children":376},{"className":375},[],[377],{"type":30,"value":378},"until?",{"type":30,"value":380}," and records ",{"type":21,"tag":45,"props":382,"children":384},{"className":383},[],[385],{"type":30,"value":386},"revertTo",{"type":30,"value":388}," = the mode it replaced. Clock passing ",{"type":21,"tag":45,"props":390,"children":392},{"className":391},[],[393],{"type":30,"value":394},"until",{"type":30,"value":396}," reverts and logs a system history line (\"Until passed · back to Enforce\"). Remove ",{"type":21,"tag":45,"props":398,"children":400},{"className":399},[],[401],{"type":30,"value":139},{"type":30,"value":141},{"type":21,"tag":45,"props":404,"children":406},{"className":405},[],[407],{"type":30,"value":147},{"type":30,"value":409}," and the snooze branch in applicability; migrate the P-NO-ROOT seed snooze to ",{"type":21,"tag":45,"props":411,"children":413},{"className":412},[],[414],{"type":30,"value":415},"mode: observe, until: 2026-11-15, revertTo: enforce",{"type":30,"value":417},". Grep the components for ",{"type":21,"tag":45,"props":419,"children":421},{"className":420},[],[422],{"type":30,"value":423},"snooze",{"type":30,"value":425}," and list every hit in your report (02\u002F04 remove them; don't edit their files).",{"type":21,"tag":102,"props":427,"children":428},{},[429,434,436,442,444,449,451,457,459,465,467,473,475,481,483,489,491,497],{"type":21,"tag":26,"props":430,"children":431},{},[432],{"type":30,"value":433},"Impact (README §4).",{"type":30,"value":435}," Rewrite ",{"type":21,"tag":45,"props":437,"children":439},{"className":438},[],[440],{"type":30,"value":441},"previewChange",{"type":30,"value":443}," to return ",{"type":21,"tag":45,"props":445,"children":447},{"className":446},[],[448],{"type":30,"value":80},{"type":30,"value":450}," (people with from→to, teams with affected\u002Fof, outOfVisibility = people whose resulting mode is Off and wasn't, tightened\u002Floosened per policy+scope, finding ids). Add ",{"type":21,"tag":45,"props":452,"children":454},{"className":453},[],[455],{"type":30,"value":456},"previewDraft(edits)",{"type":30,"value":458}," = cumulative impact of a list of changes applied in order. Keep a ",{"type":21,"tag":45,"props":460,"children":462},{"className":461},[],[463],{"type":30,"value":464},"counts(impact)",{"type":30,"value":466}," helper so today's callers (",{"type":21,"tag":45,"props":468,"children":470},{"className":469},[],[471],{"type":30,"value":472},"policy-detail.vue",{"type":30,"value":474}," l.103–109, ",{"type":21,"tag":45,"props":476,"children":478},{"className":477},[],[479],{"type":30,"value":480},"ModeControl.vue",{"type":30,"value":482}," l.78–99, ",{"type":21,"tag":45,"props":484,"children":486},{"className":485},[],[487],{"type":30,"value":488},"ResolveCapture.vue",{"type":30,"value":490}," l.29–31) can be shimmed without editing them — export the old shape as ",{"type":21,"tag":45,"props":492,"children":494},{"className":493},[],[495],{"type":30,"value":496},"previewChangeCounts",{"type":30,"value":498}," and point the old name at it only if needed to keep them compiling; note it for removal in Wave 2.",{"type":21,"tag":102,"props":500,"children":501},{},[502,507,509,514,516,522,524,530,532,538,540,546,548,554,556,562,564,570,571,577,579,585,587,593,595,601,603,609,611,617,619,625,627,633],{"type":21,"tag":26,"props":503,"children":504},{},[505],{"type":30,"value":506},"Publishing (D4, D5, D2).",{"type":30,"value":508}," In the composable: keep ",{"type":21,"tag":45,"props":510,"children":512},{"className":511},[],[513],{"type":30,"value":179},{"type":30,"value":515}," (local staging) and ",{"type":21,"tag":45,"props":517,"children":519},{"className":518},[],[520],{"type":30,"value":521},"stage\u002Funstage",{"type":30,"value":523},"; replace ",{"type":21,"tag":45,"props":525,"children":527},{"className":526},[],[528],{"type":30,"value":529},"drafts[]",{"type":30,"value":531}," with one ",{"type":21,"tag":45,"props":533,"children":535},{"className":534},[],[536],{"type":30,"value":537},"draft: { base, changes: DraftChange[] }",{"type":30,"value":539}," (DraftChange = edit + ",{"type":21,"tag":45,"props":541,"children":543},{"className":542},[],[544],{"type":30,"value":545},"author",{"type":30,"value":547}," + ",{"type":21,"tag":45,"props":549,"children":551},{"className":550},[],[552],{"type":30,"value":553},"at",{"type":30,"value":555},"), ",{"type":21,"tag":45,"props":557,"children":559},{"className":558},[],[560],{"type":30,"value":561},"saveToDraft()",{"type":30,"value":563}," moves local edits into it (same-setting line: last value wins, author updated — keep commit 06b083095's rule), ",{"type":21,"tag":45,"props":565,"children":567},{"className":566},[],[568],{"type":30,"value":569},"discardDraft()",{"type":30,"value":52},{"type":21,"tag":45,"props":572,"children":574},{"className":573},[],[575],{"type":30,"value":576},"publish(note)",{"type":30,"value":578}," = new version n+1 from pointer + all draft changes, pointer moves, log line; ",{"type":21,"tag":45,"props":580,"children":582},{"className":581},[],[583],{"type":30,"value":584},"rollback(v, note)",{"type":30,"value":586}," moves the pointer, the draft stays and is re-based (mark changes that now equal live as ",{"type":21,"tag":45,"props":588,"children":590},{"className":589},[],[591],{"type":30,"value":592},"redundant: true",{"type":30,"value":594},"). Drop ",{"type":21,"tag":45,"props":596,"children":598},{"className":597},[],[599],{"type":30,"value":600},"submit\u002Fapprove\u002Fpromote\u002FsetRequireApproval\u002FrequireApproval\u002FdraftStanding",{"type":30,"value":602}," and the ",{"type":21,"tag":45,"props":604,"children":606},{"className":605},[],[607],{"type":30,"value":608},"?draft=",{"type":30,"value":610}," preview knob → replace with ",{"type":21,"tag":45,"props":612,"children":614},{"className":613},[],[615],{"type":30,"value":616},"?preview=draft",{"type":30,"value":618}," (replay draft on every page). Seed: v12 → v13 live as today; the shared draft holds Riley's P-TRANSPORT Observe and Dana's P-ACCT Critical (the old D-6\u002FD-7 content) so the page isn't empty. Labels: export ",{"type":21,"tag":45,"props":620,"children":622},{"className":621},[],[623],{"type":30,"value":624},"configLabel(v) = 'Policy Config v' + v",{"type":30,"value":626}," and ",{"type":21,"tag":45,"props":628,"children":630},{"className":629},[],[631],{"type":30,"value":632},"pendingLabel = 'v13 · N pending changes'",{"type":30,"value":340},{"type":21,"tag":102,"props":635,"children":636},{},[637,642,644,650,652,658,660,666,668,674,676,682,684,690,692,698,700,706,708,714],{"type":21,"tag":26,"props":638,"children":639},{},[640],{"type":30,"value":641},"Fleet (D11, D12).",{"type":30,"value":643}," Replace the count map with ",{"type":21,"tag":45,"props":645,"children":647},{"className":646},[],[648],{"type":30,"value":649},"fleet: Endpoint[]",{"type":30,"value":651}," — ~100 endpoints generated deterministically from the team subjects (names like ",{"type":21,"tag":45,"props":653,"children":655},{"className":654},[],[656],{"type":30,"value":657},"mac-eng-07",{"type":30,"value":659},", reuse the ids already in ",{"type":21,"tag":45,"props":661,"children":663},{"className":662},[],[664],{"type":30,"value":665},"Rollout.reach.pending",{"type":30,"value":667}," l.207–210 and in ",{"type":21,"tag":45,"props":669,"children":671},{"className":670},[],[672],{"type":30,"value":673},"useTeamMock",{"type":30,"value":675},"), each ",{"type":21,"tag":45,"props":677,"children":679},{"className":678},[],[680],{"type":30,"value":681},"{ id, name, team, owner, os, activeVersion, lastSeen, status }",{"type":30,"value":683}," with status ∈ current | behind | offline | failed. Seed: 97 on v13, 3 behind on v12 (mac-eng-07, win-fin-02, mac-b1 — one offline, one failed, one behind). ",{"type":21,"tag":45,"props":685,"children":687},{"className":686},[],[688],{"type":30,"value":689},"propagate()",{"type":30,"value":691}," advances non-offline\u002Fnon-failed ones. Derive per-policy reach (configured→confirmed) from it: an endpoint confirms a policy's mode when its ",{"type":21,"tag":45,"props":693,"children":695},{"className":694},[],[696],{"type":30,"value":697},"activeVersion",{"type":30,"value":699}," contains that mode. Export ",{"type":21,"tag":45,"props":701,"children":703},{"className":702},[],[704],{"type":30,"value":705},"fleetSummary(v)",{"type":30,"value":707}," → ",{"type":21,"tag":45,"props":709,"children":711},{"className":710},[],[712],{"type":30,"value":713},"{ on, of, behind, offline, failed }",{"type":30,"value":340},{"type":21,"tag":102,"props":716,"children":717},{},[718,723,724,730,732,738,740,746,748,754],{"type":21,"tag":26,"props":719,"children":720},{},[721],{"type":30,"value":722},"JSON (D13).",{"type":30,"value":43},{"type":21,"tag":45,"props":725,"children":727},{"className":726},[],[728],{"type":30,"value":729},"configJson(v | 'draft')",{"type":30,"value":731}," → stable, pretty JSON: ",{"type":21,"tag":45,"props":733,"children":735},{"className":734},[],[736],{"type":30,"value":737},"{ policyConfig: { version, publishedAt, publishedBy, note }, policies: [{ id, mode, until?, severity, config }], exceptions: [{ id, policy, scope, mode, until?, reason, by, at }] }",{"type":30,"value":739},". ",{"type":21,"tag":45,"props":741,"children":743},{"className":742},[],[744],{"type":30,"value":745},"importConfig(json)",{"type":30,"value":747}," → parse, validate (unknown policy ids, bad modes, exception scope that doesn't exist, loosening without reason), stage the differences as local edits, return ",{"type":21,"tag":45,"props":749,"children":751},{"className":750},[],[752],{"type":30,"value":753},"{ ok, errors, staged }",{"type":30,"value":340},{"type":21,"tag":102,"props":756,"children":757},{},[758,763,765,771,773,778,780,786,787,793,795,800,802,807],{"type":21,"tag":26,"props":759,"children":760},{},[761],{"type":30,"value":762},"Findings.",{"type":30,"value":764}," Each finding carries ",{"type":21,"tag":45,"props":766,"children":768},{"className":767},[],[769],{"type":30,"value":770},"configVersion",{"type":30,"value":772}," at detection (map from today's ",{"type":21,"tag":45,"props":774,"children":776},{"className":775},[],[777],{"type":30,"value":259},{"type":30,"value":779}," via the version chain) and history events carry ",{"type":21,"tag":45,"props":781,"children":783},{"className":782},[],[784],{"type":30,"value":785},"kind: 'manual' | 're-evaluation' | 'system'",{"type":30,"value":739},{"type":21,"tag":45,"props":788,"children":790},{"className":789},[],[791],{"type":30,"value":792},"governance-finding-rows.ts",{"type":30,"value":794},": outcome label ",{"type":21,"tag":26,"props":796,"children":797},{},[798],{"type":30,"value":799},"Observed",{"type":30,"value":801}," (not \"Not enforced\"), keep ",{"type":21,"tag":26,"props":803,"children":804},{},[805],{"type":30,"value":806},"Enforced",{"type":30,"value":340},{"type":21,"tag":102,"props":809,"children":810},{},[811,816,818,823,825,831,833,838,840,846],{"type":21,"tag":26,"props":812,"children":813},{},[814],{"type":30,"value":815},"Bar.vue knobs.",{"type":30,"value":817}," Remove the approval toggle and ",{"type":21,"tag":45,"props":819,"children":821},{"className":820},[],[822],{"type":30,"value":608},{"type":30,"value":824}," links; keep ",{"type":21,"tag":45,"props":826,"children":828},{"className":827},[],[829],{"type":30,"value":830},"?as=you|dana",{"type":30,"value":832},"; add ",{"type":21,"tag":45,"props":834,"children":836},{"className":835},[],[837],{"type":30,"value":616},{"type":30,"value":839},". Leave a placeholder comment for 07's ",{"type":21,"tag":45,"props":841,"children":843},{"className":842},[],[844],{"type":30,"value":845},"?stage=",{"type":30,"value":340},{"type":21,"tag":92,"props":848,"children":850},{"id":849},"done-when",[851],{"type":30,"value":15},{"type":21,"tag":98,"props":853,"children":854},{},[855,881],{"type":21,"tag":102,"props":856,"children":857},{},[858,864,866,872,874,880],{"type":21,"tag":45,"props":859,"children":861},{"className":860},[],[862],{"type":30,"value":863},"npx nuxi typecheck",{"type":30,"value":865}," (or the dev server's overlay) shows no new errors in owned files; every lab page still renders (headless sweep of ",{"type":21,"tag":45,"props":867,"children":869},{"className":868},[],[870],{"type":30,"value":871},"\u002Fpages\u002Fphase4\u002Fmock\u002F{policy-detail,findings,finding-detail,changes,policies,compliance,organization\u002Fteams,organization\u002Fteams\u002Fdetail?team=eng}",{"type":30,"value":873},"), screenshot each to ",{"type":21,"tag":45,"props":875,"children":877},{"className":876},[],[878],{"type":30,"value":879},"shots\u002F00-*.png",{"type":30,"value":340},{"type":21,"tag":102,"props":882,"children":883},{},[884,886,891,893,898],{"type":30,"value":885},"Report: the list of ",{"type":21,"tag":45,"props":887,"children":889},{"className":888},[],[890],{"type":30,"value":423},{"type":30,"value":892}," hits, ",{"type":21,"tag":45,"props":894,"children":896},{"className":895},[],[897],{"type":30,"value":441},{"type":30,"value":899}," callers you shimmed, anything you had to decide.",{"type":21,"tag":92,"props":901,"children":903},{"id":902},"look-for-review",[904],{"type":30,"value":16},{"type":21,"tag":22,"props":906,"children":907},{},[908,914],{"type":21,"tag":45,"props":909,"children":911},{"className":910},[],[912],{"type":30,"value":913},"\u002Fpages\u002Fphase4\u002Fmock\u002Fchanges",{"type":30,"value":915}," shows one draft with Riley's and Dana's lines; publishing makes v14; the P-NO-ROOT row reads Observe (until 11-15).",1794599471575]