Skip to content

Releases: oernster/Decitect

Decitect v5.0.0

Choose a tag to compare

@oernster oernster released this 09 Oct 08:59

Release notes

Fulcrum is now Decitect

Same application, new name: Decitect, Decision Architecture Organisational Software. The model, board and guide are unchanged. The website is now https://decitect.com.

Your work comes with you

On first launch Decitect moves your Fulcrum settings and last session (~/.fulcrum) into ~/.decitect. If the move fails it keeps reading the old folder, so nothing is lost. Saved organisations and exported plans open as before.

Upgrading on Windows

Run the Decitect setup as usual. If it finds Fulcrum it offers, ticked by default, to remove it once Decitect is installed, taking only what provably belonged to Fulcrum: its folder, Apps list entry, shortcuts and sign-in entry. Close Fulcrum first if it is running. A Fulcrum icon pinned to the taskbar needs pinning again. Installed Fulcrum releases are offered this setup by their own update check.

Upgrading on macOS and Linux

Decitect installs alongside Fulcrum; your settings still come across. Remove the old copy afterwards: on macOS drag Fulcrum from Applications to the Bin; on Linux run flatpak uninstall uk.codecrafter.Fulcrum.

Smaller changes

The donate button now goes to Decitect's own payment page.

Fulcrum v4.6.0

Choose a tag to compare

@oernster oernster released this 04 Oct 05:53

Release notes

A hardening release: damaged or malformed files are refused cleanly instead of being half loaded, cancelling the guide now frees your processor as well as the progress bar and the promise about network use is now checked automatically.

Saved sessions you can trust

If the saved move record could not be read or no longer replayed, Fulcrum used to restore the organisation without it; the next save then wrote the file without the record, so the moves were lost unseen. Now the file as it was is kept aside first. The organisation still restores and a message on launch says that only the move record was lost and where the original file was kept. Nothing is deleted.

A saved file whose contents are the wrong shape (a list where a value belongs, a word where a number belongs) is now treated like any other unreadable file: kept aside with a message, never a failed launch.

Opening a plan

A plan file that will not read or whose moves will not replay is now refused with one message naming the problem; where a move is the cause, the message names the first move that fails. Your current session stays exactly as it was.

Numbers the model cannot score

An organisation carrying impossible values (a number that is not a number, an infinite or absurdly large count, a yes or no setting written as text) is now refused with a clear error. Before, such a team could pass every check and score a perfect 100. A team and a unit may no longer share an id.

Cancelling the guide

Cancelling a guide build on a large organisation now ends the worker processes it started, so your processor cores are free again straight away rather than finishing work nobody will read.

Network use, now checked

Fulcrum's only connection of its own is the anonymous daily check for a newer release. That was a promise held by review; it is now checked automatically every time the app is tested, so any other connection fails the build until it is argued for.

Fulcrum v4.5.0

Choose a tag to compare

@oernster oernster released this 03 Oct 03:13

Release notes

A small release: a way to support Fulcrum, a sturdier update check and documentation that says only what the app really does.

Supporting Fulcrum

Fulcrum is free and stays free, with no paid tier, no licence key and no feature held back. For anyone who wants to support its development there is now a donate button in the header, just left of the light and dark toggle, reachable from the keyboard like every other control. Pressing it hands the payment page to your browser; Fulcrum itself opens no connection for it. If your desktop declines to open a browser, the app tells you so and shows the address. The same link sits in the README and on the website.

Commercial licences

Fulcrum stays open source under GPL-3.0 with its interface under LGPL-3.0. The README and the website now say that a commercial licence for my own code can also be bought, for anyone whose project those terms do not suit.

A sturdier update check

If the window was closed while an update check was still waiting on GitHub, the answer arriving afterwards could raise an error on the background thread. It is now quietly dropped, since nobody is left to tell. This was found by reading the code rather than reported, so it is hardening rather than the fix for a crash anyone saw.

Documentation that claims only what holds

Generated levels are now described as they behave: each template is resampled in search of a great move up to a limit, so the move is sought rather than guaranteed. The macOS build instructions now describe the keychain route to notarisation as the script actually takes it. The sensitivity sweep on the website now gives its true size of 36 perturbed configurations. A new document in the repository sets out the decisions Fulcrum rests on and what each one costs.

For anyone building from source

The development guide is now DEVELOPMENT.md. The linter is pinned to the release the repository is clean under. The Windows and macOS builds now need Nuitka 4.2.1 or later and stop before compiling, naming the version they found, when an older one is installed.

The website

The tool and model pages are split into a page for each part: the moves and signals, the board and the guide, the weights, the assumptions and the testing. Old links to the long pages still land in the right place. The board screenshot is new and shows the donate button in the header. The installer and the Linux package now name ernster.dev/fulcrum as the app's site.

Fulcrum v4.4.0

Choose a tag to compare

@oernster oernster released this 09 Aug 19:59

Release notes

One new capability: Fulcrum now notices when a newer release has been
published and offers it to you, without nagging and without sending anything
about you or your organisations anywhere.

An update check that respects you

A few seconds after launch and then once a day while it stays open, Fulcrum
asks GitHub's releases API whether a newer version exists. When one does, a
prompt names the version you are on and the version available, with three
choices: Download opens the right file for your platform (the Windows
installer, the macOS disk image or the Linux Flatpak, falling back to the
release page when no matching file is attached), Skip This Version silences
that version permanently and Later closes the prompt until the next check.

Help's Check for updates used to open the releases page in your browser and
leave the comparing to you. It now runs a real check and reports every
outcome: the same prompt when an update exists, a plain "You are running the
latest version." when none does and an honest failure message when GitHub
cannot be reached. The manual check deliberately ignores a skipped version,
so a release you previously declined stays reachable.

The check is built not to intrude. Only a formally published release can
prompt; a failed or malformed check on the automatic path says nothing at all
and tries again another day. The request carries no identifier and nothing
about your organisations or your sessions. Your choice to skip a version
persists beside the theme in the same settings file. The Flatpak now carries
the network permission this needs; the README states plainly that this daily
call is the one thing Fulcrum ever asks the network.

Fulcrum v4.3.0

Choose a tag to compare

@oernster oernster released this 05 Aug 15:16

Release notes

One thing runs through this release. The gentle self-reading behaviour the
help dialogs already had now reaches every explanatory surface that can
overflow, so no part of the family is left half in it.

Experience

  • A signal's definition reads itself. The dialog behind a signal's
    magnifier button explains what the reading measures, its unit, when it
    reads high and what it maps to. On a short window, or with a longer
    definition, the tail of that sat below the fold and had to be found by
    hand. It now holds still on open, reads itself down at the same pace as
    the glossary and the licence texts, holds at the end and rewinds. Nothing
    changes for a definition that already fits: the cycle moves only when the
    content actually overflows, so attaching it to a surface that currently
    fits costs nothing.

  • The guide's move list reads itself. A frame's line can run to more
    moves than the pane shows, exactly as the board's own move list can, and
    the board's list has read itself down for some time while the guide's did
    not. The two now behave identically. Scrolling by hand, dragging the
    scrollbar or tabbing onto a move row suspends the cycle, and it picks up
    from wherever you left it, so taking over never switches the behaviour off
    for the rest of the dialog's life.

Both surfaces run on the shared constants rather than their own, which is
the point of doing it this way: one reading pace for the whole application,
so no dialog can drift into feeling faster or slower than its neighbours.

Fulcrum v4.2.0

Choose a tag to compare

@oernster oernster released this 05 Aug 01:39

Release notes

IMPORTANT NOTE:

  • macos dmg release asset removed since I forgot to notarise it (I didn't know that step was necessary after developer signing; the latest version has been notarised).

Two things run through this release. The Windows installer, which until now
sat outside every check the rest of the repository is held to, is now held to
all of them. And several places where the app quietly did the wrong thing
with your work are fixed: it reopens where you left it, it shows you where a
move landed, and it will no longer write over a saved organisation it cannot
read.

Experience

  • Dependency arrows land on the box they point at. An arrow head was
    placed by backing off half a box width horizontally and half a box height
    vertically at the same time, which is correct only when the approach is
    exactly horizontal or exactly vertical. Every diagonal dependency
    therefore had its head sitting somewhere off the target rather than on its
    edge. Both maps now meet the border properly at any angle, and each run is
    drawn from border to border rather than centre to centre, so no line is
    painted across the inside of the box it leaves or the box it enters. A
    dependency count above one is centred on its run instead of hanging off
    the midpoint.

  • The presentation's map no longer spills text out of its boxes. Every
    node on the exported before-and-after map was drawn at one fixed width,
    which was never checked against the text put inside it. A domain with
    enough teams for a four-figure count ("1,076 teams, 177 contested teams")
    needed half as much width again, so the line simply ran out past the
    border. Nodes are now sized to their own longest line, sharing the widest
    on the map so the grid stays a grid, and the map states the font it is
    measured against rather than inheriting whatever the document supplies.
    The one function producing a node's lines is now the one the sizing reads,
    so a box cannot be measured from different text than it draws.

  • Every button wears the same background. The icon buttons in the header
    and the move-preview buttons beside each move declared a transparent
    background of their own, so they read as bare glyphs sitting on the window
    while every other button in the app sat on the raised grey. Those two
    overrides are gone: there is now one rule deciding what a button looks like
    at rest, and it governs the main window and every dialog alike. The
    distinct darker fill on a disabled button is deliberate and stays, since
    that is how unavailable is signalled alongside the red ring.

  • The presentation is where you can see it, and it opens itself. Its
    button sat out on the right-hand edge among the utilities, which is not
    where the board's main output belongs; it now sits at the centre beside
    the move record and the provenance mark. Creating a presentation still
    writes it into your Downloads folder under a fresh name that never
    overwrites an earlier one, but it now opens in your browser instead of
    reporting a filename and leaving you to go and find it. The confirmation
    box remains only for the case where nothing opens the file.

Fixes

  • The app reopens on the section you were working in. It always came
    back at the whole organisation, however deep you had drilled, which on a
    large structure meant finding your way back down on every launch. Two
    things were wrong: the drilled section was never written to the autosave,
    and the board discarded whatever focus a session arrived with before
    showing it. Both are fixed, and the restored section is validated against
    the organisation that came back, so a file naming a unit that no longer
    exists or no longer holds teams opens at the whole organisation rather
    than pointing at nothing. A file written by an earlier build simply has no
    section recorded and opens as it always did.

  • A move you play is now marked on the map. Playing from the move list
    redrew the board in the new position and left no visible trace of what had
    happened. At whole-org scope that is indistinguishable from nothing
    happening at all: a repair inside one section moves the encoding by
    hundredths, which no colour can show. The nodes a move acted on are now
    ringed on both the complete picture and the drill map, and where the
    picture summarises a section, the section holding those teams is ringed
    instead. Taking a move back falls back to marking the one before it. The
    ring already existed and was used by the move preview and the move record;
    the board itself simply never asked for it.

  • The uninstaller no longer offers to delete a directory the app has never
    written.
    It looked for user state under LocalAppData while the
    application saves its settings and its session to a directory in your home
    folder. So "also remove my settings and saved games" removed nothing and
    reported success, and a full uninstall left everything behind. The two now
    agree, and a test pins them together by comparing the paths both sides
    compute, since the installer is compiled separately and cannot import the
    app to share a constant.

  • A saved organisation that will not load is kept instead of overwritten.
    The old behaviour was silent and total: any unreadable or incompatible file
    produced a fresh session, and the first thing the fresh session did was
    save itself over the file it could not read. One bad file and an
    organisation with its whole move record was gone in seconds, with no
    message anywhere. Such a file is now moved aside first, under a name that
    cannot displace an earlier rescue, and if even that fails the store refuses
    to write at all rather than destroy what it found. Either way the app now
    says what happened and where the file went.

What's new

  • The installer is gated like the application it installs. It was a
    1,575-line PySide6 program with no tests, invisible to both the coverage
    gate and the module-size gate, wearing a build script's exemption while
    carrying real logic: registry writes, path resolution, payload extraction,
    shortcut targets and the launcher resolution a onefile build needs. A
    defect in any of those lands on a machine before Fulcrum ever starts. It
    is now layered the way the app is: installer_logic.py decides and is held
    at 100% coverage by 49 new tests, installer_ops.py acts on Windows,
    installer_lifecycle.py composes the two and the Qt surface presents. No
    installer behaviour changed.
  • The 400-line cap now covers the installer too. Every module under
    installer/ is inside it. The structural suite gained two invariants:
    nothing under installer/ may import from the fulcrum package, since
    the two binaries are built and released separately; its decision layer may
    not reach for the registry, a subprocess, the environment or Qt.
  • The analysis scripts are inside the suite. calibrate.py,
    sensitivity.py and generate_matrixed_enterprise.py were covered by
    nothing, which mattered most for the calibrator: a silently broken one
    reports success. The suite now fails if the sensitivity sweep loses a
    qualitative conclusion, if a calibration case drifts outside its expected
    band or if the committed matrixed-enterprise case stops matching what its
    generator produces.
  • The matrixed-enterprise generator reads as a hierarchy. Its builder was
    one 136-line function nested five deep; it is now an accumulator and four
    named builders, at 350 lines rather than 391. The output is byte-identical
    to the committed case, which the suite asserts.
  • The repository states its own outstanding debt. TECH_DEBT.md records
    what is still open, what is deliberately left alone and what only looks
    like debt, with the reasoning for each, and the README links to it. It
    holds open items only: a resolved one is deleted rather than marked done,
    because the history of a debt is not itself a debt.
  • build_docs.py is retired. It claimed in its own docstring to be the
    authoritative source of the site while emitting a single page with no
    navigation, so running it would have overwritten the published index and
    orphaned why.html, model.html, tool.html and download.html. The
    site is hand-maintained and now says so, with nothing left to contradict
    it.

Fulcrum v4.1.0

Choose a tag to compare

@oernster oernster released this 01 Aug 18:48

Release notes

IMPORTANT NOTE:

  • macos dmg release asset removed since I forgot to notarise it (I didn't know that step was necessary after developer signing; the latest version has been notarised).

What's new

  • The presentation judges every move in its own frame too. The
    exported report classified each move against the whole organisation
    only, so a repair played as good inside a drilled section (worth
    points in its frame, hundredths at whole-org scale) read as neutral
    and the deliberate balance of a plan vanished from the report. Every
    move whose targets sit inside one unit's subtree now carries a second
    verdict: the unit is recovered from the move's own targets, scored
    before and after exactly as the board scores a drilled section and
    badged beside the org-wide verdict ("within Runtime group 2: good,
    section health 45.652 to 51.480"), with a summary note explaining the
    two scales; org-wide acts keep their single verdict. This is the
    book's own move-locality result honoured in the report: a leaf repair
    invisible from the summit is priced where it lives.
  • Rationales never claim a fall the numbers cannot show. The report
    named the signal each move most eased even when the easing rounded
    away at display precision, producing lines like "Rework rate falls
    46% to 46%". A signal now counts as easing only when its displayed
    value actually changes; when no visible easing exists the rationale
    states the health change alone.
  • The Flatpak carries the full asset set. The Linux build now ships
    the provenance icon (the golden mark beside the app icon that opens
    "What grounds the numbers") and the calibration examples, so
    Organisation | Open example organisation works in the sandbox exactly
    as it does on Windows and macOS.
  • The macOS icon ships with its glow. The disk-image build derived
    its .icns from the raw master artwork (dark ink on a dark fill), so
    the Mac icon shipped without the glow treatment the Windows and Linux
    builds carry. It now derives from the highest-fidelity glow-treated
    PNG the icon generator emits and warns plainly when none is present.

Fulcrum v4.0.0

Choose a tag to compare

@oernster oernster released this 01 Aug 17:42

Release notes

IMPORTANT NOTE:

  • macos dmg release asset removed since I forgot to notarise it (I didn't know that step was necessary after developer signing; the latest version has been notarised).

What's new

One idea defines this release, carried through eight adversarial repairs:
the score now prices authority by scale. Machiavelli holds both positions
and the model encodes their union: The Prince (concentrated authority
governs the small state well) and the Discourses (the durable large state
is an institutionalised republic), hinged on the Dunbar horizon and
grounded in the light-cone axiom rather than preference. The claim was
then attacked adversarially, every finding repaired and every repair
pinned by a conformance test, so the scale dependency is structural and
checkable rather than an asserted preference. Alongside the model: two new
signals, glossary entries for the new vocabulary, a calibration harness
for lived-experience organisations and an updated preregistration.

  • The prince band. Five new coefficients in SimulationParameters
    (dunbar_headcount 150, prince_band_upper 200, prince_attenuation 0.3,
    prince_amplification 0.25, prince_survivor_ceiling 1.6). Up to 150
    people the three authority charges (capacity cut, escalation share,
    influence divisor) cost 0.3 of their flat price; the price rises linearly
    to parity across 150 to 200, then grows with the log of the population and
    caps at 1.6. The cap is survivorship made structural: rare princes persist
    at scale, so concentration is graded, never prohibited.
  • Frames are priced at their own population. Rolled unit nodes and leaf
    frames now carry real headcounts, so a Dunbar-sized pocket deep inside a
    conglomerate may stay princely in its own frame while the frames above it
    demand a republic.
  • Contest is never forgiven. The attenuation applies only to clean
    concentration; a standing claim keeps its full flat price below the
    horizon and above the band it deepens in proportion to the scaled
    escalation price, so a contested team's capacity sits strictly below a
    merely escalating team's at every scale. This closes the adversarial
    finding that the first cut let contest and clean escalation converge to
    the same capacity price at scale.
  • A full republic is scale-invariant. A structure with local authority
    everywhere and no claims scores identically at every population; the
    band leaves the well-designed archetype column untouched (the routed
    dependent demand below moves it separately, since even a well-designed
    organisation carries supplier hubs).
  • Resolution neighbourhoods. Two adversarial findings closed in one
    mechanism. Each escalating team resolves at the nearest enclosing unit
    whose subtree holds a clean authority: its concentration charges are
    priced at that unit's population, so a team whose lead sits across the
    desk is never priced at conglomerate scale (an org of 100 empowered
    50-person pockets now reads the same headline at any unit count), and
    escalation_load_share (0.25) of its workload lands on that unit's
    authorities' queues, so a founder absorbing thirty teams' escalations
    saturates and prices itself as latency. The shed load is deliberately
    not attenuated by the band: the band forgives friction, never bandwidth.
  • Fragmentation is priced (unowned interfaces). The fourth adversarial
    finding closed: a dependency between two clean sovereigns that share no
    enclosing domain has no institutional roof under which its conflicts can
    be arbitrated, so each such edge pushes its endpoints toward the
    cannot-decide-cleanly share, weighted by unowned_interface_weight (0.5)
    and scaled by the prince factor. Two roofless founders stay near-free;
    a roofless network of 200 sovereign teams at 20,000 people falls from
    98.8 to 70.4, while the same network under a declared common roof keeps
    its score: the roof is a modelling claim that a shared owner exists.
    Machiavelli's republic is institutionalised: a senate, not merely
    distributed sovereignty.
  • Dependency concentration prices itself (routed dependent demand).
    The escalation machinery priced authority concentration while a fully
    empowered dependency hub rode free: a five-person team that thirty-four
    teams wait on read as healthy (the matrixed-enterprise sample exposed
    the gap once its Developer experience section was delegated: the hub
    fan cost about one point against the same teams in disjoint pairs).
    dependent_demand_weight (0.15) now routes that fraction of the
    frame's workload from each dependent onto its upstream's queue,
    authority notwithstanding, grounded in Little's law and LatencyLab's
    serial-queue placement result. The imbalance floor keeps a light
    fan-out free, so the cost begins where the queue does; the coefficient
    is held at or below escalation_load_share (enforced in code) since
    waiting on a supplier may never cost more than resolving through an
    authority. The 34-fan hub now prices 5.6 points below its distributed
    twin, every calibration case stays in its band and the knife-edge
    greedy great on the enterprise archetype (+9.09 against the 9.0
    threshold) honestly becomes a strong good.
  • Frames carry their roof. A focused frame previously dropped its
    enclosing domains, so every edge between two sovereign teams inside a
    drilled section read as roofless fragmentation (a fully roofed section
    showed "Unowned interfaces: 34") while the whole-org score priced the
    identical edges as roofed: the same fact, two prices. Every focused
    frame (a leaf section, an aggregate unit, a mixed unit's direct-teams
    row) now keeps its subtree's domain rows with the root cut loose from
    the world outside, so in-frame pricing agrees with the whole
    organisation; section scores rise wherever a roof genuinely stands and
    the whole-org score is untouched. The top-level frame stays roofless
    deliberately: nothing above the top level is modelled.
  • The matrixed enterprise drills sanely. The calibration sample's
    oversized sub-units (a lead plus thirty-four flat teams) now split
    into led groups of a handful of teams each, so every leaf has a sane
    span and the case reads as the drillable hierarchy it claims to be.
    The matrix claims the group leads exactly as it claims the unit and
    sub-unit leads (line leadership is dual-reported all the way down),
    so the documented-collapse shape survives the restructure and the
    case scores 16.3 inside its 0..30 band.
  • Influence is priced proportionally. The third adversarial finding
    closed: the influence divisor reads the per-team mean rather than the
    absolute load, so one no-authority advisory hub with ten dependents
    costs a 5,000-person organisation 3.4 points instead of half its score.
    A knock-on stated honestly: the approval-layer blunder softens on the
    large archetypes (enterprise -2.59 vs best repair +3.15 with dependent
    demand priced), so the site now says a blunder erases most of the best
    repair rather than outweighs it.
  • Archetypes carry a Company roof. All ten example organisations now
    declare the common domain their real counterparts have, which is what
    keeps the well-designed column's sovereign interfaces owned.
  • Claims are priced proportionally. The claim divisor reads the
    per-team mean like the influence divisor, so a standing claim costs the
    share of the organisation it contests rather than a flat tithe: one
    claim on a 5,000-person org costs about a point, not nine.
  • Shed load follows the wiring. A resolving authority receives the
    escalations it actually has dependencies with, so a disconnected puppet
    authority absorbs nothing and cannot launder a saturated founder's
    queue; wiring the puppet in costs coupling on both ends. Escalators with
    no edge to any resolving authority fall back to an equal split.
  • A roof needs an officer. A shared domain owns its sovereigns'
    interfaces only when its subtree holds a clean authority beyond the two
    endpoints, so two sovereigns alone under a nominal roof stay unowned.
  • A claim is strictly additive. Contested no-authority teams still
    shed their escalations (a claim disputes who clears the queue, it never
    drains it), structural sovereignty keeps an unowned edge unowned when a
    claim lands on it and the matrix-overlay actor is now an unmodelled
    claimant beside the delivery graph rather than a team, so imposing an
    overlay can never dilute the per-team means or relieve a loaded centre.
  • Two new signals. Centre escalation load (the escalated decisions per
    turn landing on the most loaded authority) and unowned interfaces, each
    with its own definition and tooltip, so the new pricing is observable in
    the app rather than silent.
  • Glossary grows the new vocabulary. The prince band and the Dunbar
    horizon, resolution neighbourhoods with escalation load and unowned
    interfaces, in the same plain register as the rest.
  • Calibration harness. python calibrate.py scores the organisations
    in examples/calibration/ against expected bands drawn from known
    outcomes, with a template for adding lived-experience cases; three
    synthetic seed cases mark the healthy, saturated and matrixed shapes.
    Each case is a real drillable hierarchy whose leaf teams hold three to
    eight people with varied sizes: the startup's eighteen squads group
    under three tribes and the enterprise is generated deterministically
    (generate_matrixed_enterprise.py, seeded) as eight divisions, 45
    domains and about 1,100 small teams with the matrix claiming every
    line lead, so drilling into any case shows real structure at every
    level. Calibration cases are permanently ineligible for the
    preregistered blind validation, stated in ...
Read more

Fulcrum v3.0.0

Choose a tag to compare

@oernster oernster released this 26 Jul 15:28

Release notes

IMPORTANT NOTE:

  • macos dmg release asset removed since I forgot to notarise it (I didn't know that step was necessary after developer signing; the latest version has been notarised).

What's new

Three changes define this release. Fulcrum can now model the disease the
books call most interesting: matrix and dual-reporting structure,
represented as authority claims and priced by the same deterministic engine
as everything else. The guide became a plan for every level of the
organisation at once, honest about what composes and what merely looks good
from altitude. And the session became a record: move history survives
closing the app, undo reaches across runs and the exported report covers
everything ever played. Alongside them, the site gains a page that
publishes every scoring coefficient with its provenance.

  • Authority claims. A claim records another actor asserting the right to
    decide for a team: a second reporting line, a functional chapter, a matrix
    overlay. The claimant can be a team, a unit at any level or a plain label
    for someone not modelled at all (a "Head of QA" need not sit on the
    delivery graph to contest a decision class). A team's own authority is
    never a self-claim; Ships without asking stays the single source of truth.
  • Contested ownership is priced, three ways. Every decision class already
    has a structural owner (the team itself, or the line it escalates to), so
    any standing claim makes its subject contested: who decides must be settled
    before anything can be decided. A contested team's capacity takes a
    dedicated penalty that is validated never to be gentler than clean
    escalation, it counts in the escalation share and the whole score divides
    per standing claim. An org without claims scores exactly as before, pinned
    by a golden test over the ten example archetypes.
  • New moves, from great repair to canonical blunder. Resolve authority
    collapses a contested class into a single accountable owner, in the team's
    favour or a claimant's, either way leaving one resolvable worldline.
    Downgrade a claim turns a claimant into a consulted party: an explicit
    dependency with a priced delay, an interface rather than shared control.
    Impose a matrix overlay is the new standing blunder beside the approval
    layer: a second claimant lands on every team at once, so the falsifiable
    claim has a twin (model a realistic org where dual reporting improves
    structural health and the framework is wrong). A claimed team never gets a
    plain delegate move, because granting authority without settling the claims
    adds a claimant instead of removing one.
  • Contest is visible everywhere. A fifth watched signal (Contested
    ownership) counts claimed teams; contested nodes border red on the org map,
    the complete picture and the exported SVG, with "contested" in their
    status line; a unit rolls up how many of its teams are contested; the
    glossary explains claims in plain language with the same tooltip source as
    the rest of the app.
  • Claims in the editor and on disk. The organisation editor gains an
    authority-claims table beside the dependency table: pick a claimant (any
    team or unit) and the team whose decisions it claims, with illegal rows
    flagged in red and ignored rather than blocking OK. Claims round-trip
    losslessly through Edit my org, the autosave and JSON import and export,
    imported free-text claimants included; older files without claims load
    unchanged.
  • The guide now plans every level at once. "Show the guide" opens a
    two-pane tree of the whole hierarchy: every leaf row is badged with its
    line's worth in whole-org points (the honest currency: the composing
    badges sum to the headline), while a frame's own 0 to 100 climb appears only in the
    detail pane with its scale stated plainly, so a section's private "50 →
    99" never reads as a promise the whole organisation cannot keep. Leaf
    lines act on real teams and compose, so the header states an honest
    whole-org before and after from playing every leaf line; an aggregate row
    is labelled as the view from that altitude and never counted toward the
    headline, because its gains overlap the leaf repairs beneath it. Planning
    runs on a worker thread, every step states its before and after score on
    the frame's scale and any step previews and plays in place. The
    grow toggle prices growth where the edges it relieves are visible: a
    whole-organisation growth row planned against the real organisation from
    the position after every leaf line, appended as the tree's last
    composable row with its badge being growth's worth on top of the other
    lines, plus split and add moves inside aggregate frames for the real
    teams standing in them (a loose team at the top level), since those
    frames are where cross-unit edges are priced; when growth improves no
    line anywhere the guide states that plainly and a frame whose own line
    growth cannot improve says so in its detail pane, so a dependency-free
    section never reads as a dead toggle. The planner also never
    names the identical move twice in one line: replaying a partial repair
    converges with diminishing gains and read as noise.
  • Every team now counts in the guide. A team held directly by a unit
    whose child units also hold teams used to vanish from the plan entirely:
    no aggregate view rolled it up and no leaf line contained it, so its
    repairs never reached the headline. Such teams now stand as real nodes in
    their unit's view and get their own composable "Teams directly in" row
    (the top level gains one for its loose teams), restoring the rule that
    every team sits in exactly one leaf row. Their claims travel with them,
    so a contested direct team is never offered a delegate that would bypass
    the contest.
  • A leaf line composes only when it pays its way. A line that is this
    frame's own best play can still cost the whole organisation once composed
    (merging healthy teams raises the weight of every problem elsewhere), so
    composition now prices each line against the composed position and leaves
    a net-harmful line out of the headline, keeping its row and badge but
    flagging it as not composing with its cost stated. The header says
    plainly when any line was left out.
  • Stabilise interfaces is now scoped to its frame. The move carries its
    frame's nodes and thins only the edges that frame prices: played inside a
    unit it steadies that unit's interfaces; played at the top level it
    steadies the boundaries between units, unit-level dependencies included.
    Previously it thinned every dependency in the organisation from any scope.
    Saved plans replay unchanged (an untargeted move keeps the old meaning).
  • The move column runs the full height of the board. The available-moves
    list now starts at the top of the window, headed by the Play this level
    button, so more moves and signals are visible without scrolling; the score
    block sits with the map on the left and the keyboard ring follows the new
    reading order. Every splitter in the app now draws one standard visible
    divider colour with clear space either side and both scrollbar
    orientations match it, so no native light strip breaks the theme.
  • Move history survives closing the app. The autosave now records the
    starting organisation and every move beside the current org (older saves
    load unchanged), and the next launch rebuilds the session by replaying
    them, so Take a move back walks through earlier runs' moves too, all the
    way to the original organisation. Every play and take-back saves
    immediately, so the record survives however the app ends. The presentation
    covers the whole record with earlier runs' moves marked apart from the
    current run's by colour (a grey rail against an amber one, with a legend
    and counts), it is written straight into the Downloads folder under a
    fresh name with no save dialog and creating it is available whenever any
    move exists in the record, not just after a move this run. Undoing a
    historic move rewrites the record: it stops being an earlier run's move.
    Replacing the organisation (new random, wizard, import or an edit) starts
    a fresh record for the new structure; an imported plan's moves arrive as
    its record. Every move is named at the moment it is played (against the
    organisation it acted on, since a later collapse can rename its targets)
    and the note under the map now reads "Last move played: ..." with that
    name, adding "(in an earlier run)" when the move is restored history, so
    it always says exactly what it explains.
  • The complete picture routes its dependency lines cleanly. An edge
    whose straight line would cut through unrelated boxes now leaves its
    source's right side, runs down its own clear lane beyond the diagram and
    enters its target from the side with the arrow, while an unobstructed
    edge keeps its straight line; nothing is ever drawn through a box it has
    nothing to do with. Where one line crosses another, the horizontal run
    hops the vertical with a small semicircle, the circuit-diagram convention
    for wires that do not meet, and a box with several connections fans them
    out along its edge (ordered by where each counterpart sits) so parallel
    runs never overlap. A hub with more connections than its edge can present
    merges them into one counted trunk per direction ("× 10" into the box on
    a single shared lane), so neither the box edge nor the lane gutter ever
    drowns in lines.
  • The installer hands the app the foreground again. After launch on
    finish, the installer now waits for the app's window to appear and fronts
    it before closing itself; previously the window could arrive after the
    installer had gone and Windows left it flashing on the taskbar.
  • **A drill...
Read more

Fulcrum v2.0.0

Choose a tag to compare

@oernster oernster released this 23 Jul 19:06

Release notes

IMPORTANT NOTE:

  • macos dmg release asset removed since I forgot to notarise it (I didn't know that step was necessary after developer signing; the latest version has been notarised).

"Model my organisation" is redesigned around a two-pane
explorer-style editor and every model becomes reopenable, so the single worst
defect of the old editor (a mistake meant starting again) is gone.

  • A two-pane editor. The left pane is the org tree itself: units
    (Company, Group, Division, Department, Domain or your own label) nest to any
    depth with teams as leaves, each row showing a rolled-up badge such as
    "3 teams · 24 people". The dialog opens at nearly the full size of the app
    window and can be maximised, so a large organisation gets a workspace that
    scales with it; the split between the structure and the dependencies table
    is draggable. The right pane is an inspector for the selected item.
    The footer carries a live whole-org rollup and OK stays disabled (with the
    reason shown) until the model has at least one team. A unit with no teams
    beneath it shows a warning badge on its own row; hovering the row explains
    it, so the signal sits on the content rather than far away in a footer.
  • Explorer-style building. The New dropdown (or a right-click on empty
    space) starts a top-level item as any type, Company down to a single team;
    • or the context menu adds items inside any
      unit and each item's Type dropdown makes it a Division, Department, a
      custom label or a Team, converting it in place with its auto name following
      ("Team Gamma" becomes "Division Gamma"). Placeholder names run the Greek
      alphabet (Team Alpha, Team Beta, on to Omega then Alpha 2) in the editor
      and the wizard, rather than bare numbers. Rows drag like folders: onto a unit to
      move inside, between rows to reorder, Ctrl held to copy. Illegal drops (a
      tier above its parent, anything into a team, an item into its own subtree)
      show the forbidden cursor, so the nesting rule teaches itself.
  • Edit my org. A new button and File menu entry reopen the current
    organisation in the same editor fully populated, whatever its origin
    (wizard, JSON import, random generation or a previous edit). Edit, OK,
    rescore. "Model my organisation" still starts fresh and now confirms first
    when that would discard user work.
  • The model survives a restart. The current org autosaves to a per-user
    file and is restored on the next launch, so Edit my org works across
    sessions. Behind the scenes the editor is a pure function of the same
    blueprint shape the JSON import uses, which is what makes the round trip
    lossless.
  • Leads and owners are never blank. A built-in pool of over 200 full
    names (gender balanced, culturally varied, UK-weighted) fills every lead
    and owner across the editor, the wizard and random generation. Focusing a
    name field selects the whole value so a real name overtypes it in one
    motion and a dice button rolls a different one.
  • Terms explain themselves. Incentive skew, ships without asking, the
    four watched signals and the workload setting now carry plain-language
    tooltips with a concrete example each, rendered from the same source as the
    decision glossary.
  • Dependencies at any level. A dependency can now link any two items:
    team to team as before, unit to unit or across levels (a division blocked
    on a single platform team). The editor's dropdowns list teams and units by
    path; an item can never depend on itself or on its own container or
    contents, and an illegal row is flagged in red and ignored rather than
    blocking OK. A unit-level dependency counts in the frames where both its
    endpoints appear as nodes: it merges into the drilled map's arrows and the
    aggregate scores, draws between the unit boxes on the complete picture and
    is deliberately not converted into synthetic team queues, so the flat
    team-level score stays honest. Rank is not policed: a division waiting on
    one team is the bottleneck the score exists to expose.
  • The top level is playable. A "Play this level" toggle beside the map
    caption scores the top level as its own frame: each top-level unit rolls
    into one actor, loose teams stand as themselves and dependencies between
    root units are priced there, completing the rule that an edge counts
    wherever both its endpoints are nodes. The headline score stays the flat
    team-level truth; "Score the whole org" switches back. The guide follows
    the same frame, so a plan opened at the top level recommends unit-scale
    moves.
  • Plain-English polish. Counts pluralise correctly everywhere including
    the exported presentation ("over 1 move", never "1 moves"), signal
    readings drop their internal unit names in the chips and in plan
    rationales ("Escalations per release: 2", "Rework rate: 30%" and
    "falls 7 -> 6" rather than "2.0 count", "30.0 percent" and
    "falls 7.0 -> 6.0") and the glossary's move-classification
    entry now states the exact point ranges behind great, good, neutral, bad
    and blunder, taken from the same thresholds the engine uses, and explains
    that deltas are scored within the focused section. When an aggregate scope
    offers nothing better than neutral, the moves panel says the value lives
    deeper and points at the map (and no longer claims a flat org can drill).
  • Structure operations. Duplicate, Move up, Move down and Move to sit on
    the tree's context menu; removal confirms with what would be lost ("Remove
    Division 1 and its 2 teams, 16 people?"); dependencies and their delays are
    preserved through every edit, and removing a unit prunes any dependency its
    subtree carried.
  • Fit and finish. The tree's + and minus glyphs are optically centred in
    their buttons at every UI scale; the Type dropdown opens cleanly on click
    instead of bouncing shut; every button that carries a dropdown menu shows
    the same arrow as the spinboxes, so there is one disclosure cue across the
    app.
  • A three-state ring model and a calmer palette. Controls show no ring at
    rest, a green ring while hovered or keyboard-focused and enabled ("you can
    use this") and a permanent red ring while disabled, across the app, its
    dialogs and the installer. Amber is never a ring: it keeps carrying meaning
    only (the score, authority encoding on the map, checked states). The map's
    teal hover and change rings become a muted green, its keyboard cursor ring
    matches and the primary button drops its light blue fill for the standard
    dark one.

Existing JSON imports load unchanged and scoring is untouched: the same model
produces the same score as 1.4.3.

Licence

Dual-licensed by component: the model under GPL-3.0 and the user interface under
LGPL-3.0. Both texts ship with the app and are shown under Help.