Skip to main content

Good Planning

@magistr/good-planningv2026.08.02.1· 5d agoMODELSSKILLS
01README

Good-planning model that operationalizes Felipe Bovolon's "Good Planning Bad Planning" four-layer architecture as queryable swamp state. Strategy chooses; planning commits — this model holds the commitment.

Article: https://bovolon.substack.com/p/good-planning-bad-planning

A plan is not a slide deck. The article's thesis: the real plan is the pattern of commitments the organization has actually funded, sequenced, protected, and agreed to review. This model makes those commitments first- class state with explicit assumptions, signposts, tripwires, ceiling trigger points, and a pullback ladder — so the plan can be evaluated and revised on a cadence rather than executed-as-written until reality breaks it.

Four Layers (from the article)

  • Layer 1 — Assumption: what the plan believes about the world. Each assumption has impact, vulnerability, and a signpost.
  • Layer 2 — Allocative: what is actually funded and protected. Targets, forecasts, and allocations are tracked separately (Beyond Budgeting).
  • Layer 3 — Coordinative: how commitments interlock. Captured via dependsOn on each commitment.
  • Layer 4 — Adaptive: how the plan revises. Ceiling discipline (first-binding crux + trigger formula) and floor discipline (signposts → tripwires → pre-authorized actions
    • pullback ladder + max tolerable loss).

State Machine

drafted ──[commit]──> committed     (gated: all four layers populated)
committed ──[monitor]──> monitoring
monitoring ──[evaluate]──> monitoring  (read signposts, update layer state)
monitoring ──[trigger]──> adapting     (tripwire fired or ceiling crossed)
adapting ──[adapt]──> committed        (pullback or option exercised)
adapting ──[revise]──> drafted         (assumption broken — re-plan)
committed ──[archive]──> archived
monitoring ──[archive]──> archived

commit is the gate the article calls for: it refuses to leave drafted unless every layer is materially populated, including the six properties on every commitment (owner, resource, time, dependencies, review rule, consequence-if-changed) and at least one tripwire on the floor side.

Methods

  • start — create a draft plan with strategicChoice + horizon
  • add_assumption — record an assumption with impact / vulnerability / signpost
  • add_commitment — record a commitment or hypothesis (six-property gate)
  • add_allocation — record protected budget per priority (Layer 2)
  • add_ceiling — record a first-binding crux + lead time + signpost
  • add_tripwire — record a signpost threshold + pre-authorized action
  • set_pullback_ladder — ordered list of cuts (what to cut first)
  • set_loss_budget — sunk + shutdown + liabilities + working-capital + tail
  • commit — gate; transitions drafted → committed
  • monitor — committed → monitoring
  • evaluate — read a signpost; updates assumption/tripwire/ceiling state
  • trigger — explicit transition into adapting (action required)
  • adapt — record adaptation taken; back to committed
  • revise — assumption broken; back to drafted
  • archive — terminal
  • hydrate — write a compact governability scorecard summary
  • audit — answer the four diagnostic questions (one per layer)
02Release Notes

2026.08.02.1

Real-fix wave for the eight GP-1..GP-8 bugs pinned by the prior release's adversarial suite (same wave as sibling extensions seadex and victoriametrics, both already at 2026.08.02.1). Model version bumped 2026.07.16.22026.08.02.1 with an upgrades[] entry; resource schema unchanged (upgradeAttributes: (old) => old).

  • GP-1 fixed (MEDIUM) — start() now reads the existing current resource before writing. If a plan already exists it throws (naming its state/planVersion) instead of silently wiping it — pass the new force: true argument to intentionally discard an existing plan and start fresh.
  • GP-2 fixed (MEDIUM) — adapt() now resets the tripwire matching triggeredBy back to "dormant" when it was "fired", so a stale re-trigger() after adapt()monitor() correctly rejects with "No fired tripwire" until a fresh evaluate() fires it again.
  • GP-3 fixed (MEDIUM) — commitmentSatisfiesSixProperties's byDate check no longer relies on Date.parse's engine-defined leniency. It now requires a strict ISO-8601 calendar date or date-time (z.iso.date() / z.iso.datetime()); "2026" and "next quarter" are both rejected, "2026-09-01" still accepted.
  • GP-4 fixed (LOW) — evaluate() now rejects a mismatched-layer payload (e.g. timeToCruxWeeks for a signpost with no matching ceiling) instead of silently dropping it, naming the offending field and the layer it needs.
  • GP-5 fixed (LOW) — commitGateReport, governabilityScore, and auditDiagnosticQuestions.layer1Visible now share one hasLiveAssumption predicate that excludes state:"broken" assumptions. A plan whose every assumption is broken now fails the commit gate and scores Layer-1 absent; a plan with at least one non-broken assumption still scores it present.
  • GP-6 fixed (LOW) — tripwire.pullbackRung is now bounds-checked against a non-empty pullbackLadder: add_tripwire rejects a rung past the current ladder length, and set_pullback_ladder rejects a ladder too short for an already-referenced rung. A rung recorded before any ladder is set (deferred) and pullbackRung:0 against an empty ladder both stay legal — required by the frozen contract fixture.
  • GP-7 fixed (LOW) — every add_* method (add_assumption, add_commitment, add_allocation, add_ceiling, add_tripwire) is now idempotent: a structurally-identical repeat call is a no-op (still returns a handle); a call differing in even one field still appends normally.
  • GP-8 fixed (LOW) — computeTriggerPoint and computeMaxTolerableLoss now throw on non-finite (NaN/Infinity) inputs instead of propagating them through the arithmetic. The method-arguments zod boundary already rejected both for plain z.number() fields; these two guards close the gap for direct calls to the exported pure helpers.
  • Rewrote the eight GP-* pins in good_planning_adversarial_test.ts from "asserts the buggy behavior" to "asserts the fixed behavior", and added idempotence (GP-7), force:true (GP-1), strict-date (GP-3), and ladder-bounds (GP-6) positive-path tests alongside them. The frozen contract suite good_planning.test.ts and the methods/coverage/ property suites are unchanged (traced call-by-call; every exercised path uses matching-layer payloads, distinct add_* args, finite numbers, and a fresh-context start).
  • quality.yaml: re-stamped from a live swamp extension quality run; dropped the prior release's "byte-frozen / no behavior change" wording now that this release ships real fixes. All five suites stay present; ratchet stays 100 / "Grade A".
03Models1
@magistr/good-planningv2026.08.02.1extensions/models/good_planning.ts
fn start(strategicChoice: string, horizon: string, notes?: string, force: boolean)
Create a draft plan with strategicChoice + horizon. Strategy
ArgumentTypeDescription
strategicChoicestringThe where-to-play / how-to-win sentence in one line
horizonstringe.g. '3y', '12m'
notes?string
forcebooleanSet true to intentionally replace an existing plan. Without
fn add_assumption(statement: string, signpostName: string, signpostExpr?: string, lastReading?: string)
Record a Layer 1 assumption with impact, vulnerability,
ArgumentTypeDescription
statementstring
signpostNamestring
signpostExpr?string
lastReading?string
fn add_commitment(description: string, owner: string, budgetUsd: number, byDate: string, dependsOn: array, reviewCadence: string, consequenceIfChanged: string)
Record a commitment OR hypothesis with all six properties.
ArgumentTypeDescription
descriptionstring
ownerstring
budgetUsdnumber
byDatestring
dependsOnarray
reviewCadencestring
consequenceIfChangedstring
fn add_allocation(priority: string, protectedBudgetUsd: number, target?: string, forecast?: string, raidLog: array)
Record a Layer 2 protected allocation. Target / forecast /
ArgumentTypeDescription
prioritystring
protectedBudgetUsdnumber
target?string
forecast?string
raidLogarray
fn add_ceiling(crux: string, leadTimeWeeks: number, safetyMarginWeeks: number, signpostName: string, optionPremiums: array, lastTimeToCruxWeeks?: number, lastTriggerPointWeeks?: number)
Record a Layer 4a ceiling: first-binding crux + lead
ArgumentTypeDescription
cruxstring
leadTimeWeeksnumber
safetyMarginWeeksnumber
signpostNamestring
optionPremiumsarray
lastTimeToCruxWeeks?number
lastTriggerPointWeeks?number
fn add_tripwire(signpostName: string, thresholdExpr: string, preAuthorizedAction: string, pullbackRung?: number, lastReading?: string)
Record a Layer 4b tripwire: signpost + threshold + pre-authorized
ArgumentTypeDescription
signpostNamestring
thresholdExprstring
preAuthorizedActionstring
pullbackRung?number
lastReading?string
fn set_pullback_ladder(rungs: array)
Record the ordered list of cuts. Index 0 is what gets
ArgumentTypeDescription
rungsarray
fn set_loss_budget(sunkCostUsd: number, shutdownCostUsd: number, committedLiabilitiesUsd: number, workingCapitalUnwindUsd: number, tailProvisionsUsd: number)
Record the maximum tolerable loss components. Total = sunk +
ArgumentTypeDescription
sunkCostUsdnumber
shutdownCostUsdnumber
committedLiabilitiesUsdnumber
workingCapitalUnwindUsdnumber
tailProvisionsUsdnumber
fn commit()
drafted → committed. Refuses unless every layer is materially
fn monitor()
committed → monitoring. Begin signpost evaluation.
fn evaluate(signpostName: string, reading: string, timeToCruxWeeks?: number)
Read a signpost's current value and update every assumption,
ArgumentTypeDescription
signpostNamestring
readingstringObserved value, free-form string
timeToCruxWeeks?numberIf reading impacts a ceiling: observed weeks until crux.
fn trigger(signpostName: string, reason: string)
monitoring → adapting. Call when a tripwire has fired or a
ArgumentTypeDescription
signpostNamestring
reasonstring
fn adapt(triggeredBy: string, actionTaken: string, reason: string, reading?: string, exercisedCeilingCrux?: string)
adapting → committed. Record the action taken (pullback rung
ArgumentTypeDescription
triggeredBystringSignpost name or ceiling crux that caused the adapt
actionTakenstring
reasonstring
reading?string
exercisedCeilingCrux?stringIf the action exercised a ceiling option, name the crux to mark it
fn revise(reason: string, brokenAssumptions: array)
adapting → drafted. An assumption has broken; the strategic
ArgumentTypeDescription
reasonstring
brokenAssumptionsarray
fn archive(reason: string)
Terminal. committed or monitoring → archived. Plan is no longer
ArgumentTypeDescription
reasonstring
fn audit()
Answer the four diagnostic questions from the article (Layer 4
fn hydrate()
Write a compact governability scorecard summary. Does

Resources

state(infinite)— Plan state — strategic choice, four-layer collections, history
summary(infinite)— Compact governability scorecard written by `hydrate`.
04Skills1
good-planning2 files
05Previous Versions3
2026.07.16.2

Release 2026.07.16.2 — align model versions with manifests

Maintenance release across the @magistr extensions. For most packages this carries no functional change: the only edit is the model's version: field, brought back in line with its manifest version so the published model type version and the package version no longer drift.

Functional changes in this release are limited to:

  • anime-cron: normalizeTitle now strips a ": subtitle" suffix and a trailing parenthesized year before comparison, fixing dedup false-misses where the torrent title carries a subtitle or year that the AniList romaji does not.

  • arckit: first publish. Standalone ArcKit port — a 12-phase architecture governance state machine with 65 bundled templates, driven by a bundled skill.

Also tracks three extensions (kaiten, observability-agent, music-library) that previously existed only as untracked working-tree directories, recovered from stashes.

Added 1, removed 1 models. Added 1 skills

2026.05.01.1

2026.05.01.1 — Add article link to extension description

Surface the source article URL directly in the manifest description so the swamp.club extension page links to it without forcing readers into the README:

Article: https://bovolon.substack.com/p/good-planning-bad-planning

The link was already present in README.md, SKILL.md, and the model source file as a citation, but missing from the manifest description that drives the registry summary card. No code or schema changes — this is a metadata-only release.

2026.04.30.1
06Stats
A
100 / 100
Downloads
24
Archive size
35.4 KB
  • Has README or module doc2/2earned
  • README has a code example1/1earned
  • README is substantive1/1earned
  • Most symbols documented1/1earned
  • No slow types (deprecated)1/1earned
  • Dependencies pass trust audit2/2earned
  • Has description1/1earned
  • Platform support declared (or universal)2/2earned
  • License declared1/1earned
  • Verified public repository2/2earned
07Platforms
08Labels