feat(git): land the git mapping — the exec grammar + the alkgit dispatch (w3-git-mapping)
- dispatch: the full exec grammar replaces the wave-2 skeleton probe (quoted/unquoted paths, the .git normalization decision, unknown- service / service-only decline-with-reason class; the probe's unit rows migrate with their pinned verdicts preserved) - git_map: the git row dispatches serve_duplex_resolved over the channel duplex (repo id validated, never resolved; the exit-status mapping 0/1 decided per POC-3 §A.5; status before close from the spawned task), with the resolved identity riding the seam - handler: the store-and-take channel handoff (stored at the open, taken in the spawned serving task, released at close) and the max_exec_command_len pre-parse cap - config course correction: GitSeam carries the assembly-supplied alkgit Limits (the ADR-009 budget alkgit's contract assigns the assembler) - tests: tests/git_mapping.rs (byte-level process-mode advertisement, ls-refs round + exit 0, the collapsed-denial byte-order + exit 1, the identity-ride authorize-gate witness, the packless CAS push, the grammar/cap decline rows, the sequential-serve store row, and the real-tool git 2.43 clone smoke over a TCP mount with a skip-with-reason posture); dispatch_core/observe rows updated to the new decision set; tests/common/git_doubles.rs (the hand-rolled recording alkgit quartet) Verification: cargo test (default), --features session, --features git, --all-features; clippy -D warnings ×2; fmt --check; cargo doc --no-deps; taskgraph validate
This commit is contained in:
1 parent
58d0b86ec5
commit
7aac2d11a2
12 files changed
+2012
-173
No files matched your search
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: w3-git-mapping
|
||||
name: Wave 3 — the git mapping (exec grammar + alkgit dispatch)
|
||||
status: pending
|
||||
status: completed
|
||||
depends_on: [w3-decline-tracing]
|
||||
scope: moderate
|
||||
risk: medium
|
||||
@@ -121,4 +121,116 @@ contract.
|
||||
|
||||
## Notes
|
||||
|
||||
> To be filled at implementation time.
|
||||
> To be filled at implementation time.
|
||||
|
||||
### Decisions recorded (implementation, 2026-10-28)
|
||||
|
||||
- **Course correction to `w3-seam-config`**: `GitSeam` gains
|
||||
`limits: alkgit::Limits` — `serve_duplex_resolved` requires the
|
||||
alkgit ADR-009 session budget, which the landed handle had no field
|
||||
for. alkgit's own contract shapes this ("constructed by the
|
||||
door/adapter from assembler config"), so the budget rides the seam
|
||||
(assembly-supplied, `Copy`), not a crate default. First seam
|
||||
consumer; landing it here, recorded on the field and in the config
|
||||
docs.
|
||||
- **The grammar** (`dispatch.rs`, the probe's rows migrated): exact
|
||||
serving-service token + single separating space + path-shaped
|
||||
argument (the wave-2 probe's pinned verdicts preserved verbatim —
|
||||
`git-upload-pack rel` and double-space arguments are *not git*);
|
||||
quoted shape is fully `'`-wrapped (unterminated → pipe, the probe's
|
||||
non-path-shape verdict); leading `/` stripped after quotes; **one
|
||||
trailing `.git` suffix stripped** (the vanilla-clone idiom; the
|
||||
alkgit registry grammar excludes `.`, so the door normalizes the
|
||||
idiom rather than asking registries for dotted keys; an empty
|
||||
remainder — `/.git` — is *kept* and the git row's validation
|
||||
declines it, never a silent emptying). Validation:
|
||||
`alkgit::validate_repo_id` at the git row (`git_map.rs`,
|
||||
feature-gated — the parse core stays feature-free); a shape-invalid
|
||||
id declines `invalid-repo-id` alkssh-side; a shape-valid id is
|
||||
handed through untouched and **alkssh never resolves** (resolution,
|
||||
authorize, and the collapsed generic denial live at the seam).
|
||||
Unknown services (`git-send-pack`, `git-upload-archive`) and
|
||||
service-only (including an empty argument) route to
|
||||
`ExecRoute::Declined` — build-independent, off the pipe row, per
|
||||
POC-3 §2's honest-surface verdict.
|
||||
- **Wire shapes per decline class** (recorded): SSH request replies
|
||||
carry no text, so the reason lives only in the event vocabulary;
|
||||
the git declinables (`unknown-service` / `service-only` /
|
||||
`invalid-repo-id` / `exec-oversize`) share the request-level reply
|
||||
shape with parse-then-fail — `channel_failure`, channel alive
|
||||
(POC-3's decline shape, POC-1 §5 posture); the reply vocabulary is
|
||||
the decision ("unknown service" vs "not git at all" differ in
|
||||
nothing observable on the wire — only the event). Serving-path
|
||||
declines (the row owned the channel) keep failure+close:
|
||||
`seam-unconfigured` (feature on, seam unset — the unset-declines
|
||||
contract; keeps the wave-2 decline-matrix rows' shape in builds
|
||||
without a configured seam), plus the unreachable-in-practice
|
||||
guards `no-identity` and `channel-not-held`. The *serve's own*
|
||||
denials are not alkssh declines: unknown/ungranted repo flows to
|
||||
alkgit, whose collapsed generic denial writes
|
||||
`ERR access denied: <repo>` as the **first byte** on the channel
|
||||
(pinned byte-level in `tests/git_mapping.rs`), then exit-status(1),
|
||||
then close.
|
||||
- **Exit mapping** (POC-3 §A.5, decided): `Ok(())` → exit-status(0)
|
||||
(vanilla git exits 0 on success; the clean-end wire row exercises
|
||||
the flush-only request's `Ok(None)` → `Ok(())` shape); every
|
||||
`SubstrateError` → exit-status(1) — `AccessDenied` per the POC's
|
||||
wire evidence, `Io`/`Protocol` the same (the service ran and
|
||||
failed), the machinery-misuse variants defensively 1 (they never
|
||||
arise from the serving entry). `255` never fabricated (OpenSSH's
|
||||
could-not-start semantic this door never claims). Status before
|
||||
close, from the spawned task via the cloned handle; a failed report
|
||||
send is the vocabulary's one `warn` (the wave-2 stub mechanics). A
|
||||
serve `Err` is *not* a decline event — the substrate already mapped
|
||||
its own error onto the wire.
|
||||
- **Store-and-take handoff**: `SessionHandler.channels` (plain
|
||||
`std` HashMap, single-writer — every mutation on the packet loop's
|
||||
task). Stored at the confirmed open (accept then insert); taken by
|
||||
the git row (`remove` → `into_stream()` in the spawned serving
|
||||
task); released by `channel_close` (the cap is released there too —
|
||||
one hook, both budgets). The session rows still hold until their
|
||||
wave-3 tasks take them. A routed exec answers `channel_success`
|
||||
inline (the POC-3 §A.5 shape — the request routed; the serving
|
||||
outcome reports through exit-status).
|
||||
- **Identity** (`w2-auth-bridge`'s parked ride-along, discharged):
|
||||
the resolved identity is cloned into the serving task and passed on
|
||||
`serve_duplex_resolved`'s identity param. The cheapest live witness
|
||||
row: **alkgit's `authorize` evaluation** — two otherwise-identical
|
||||
rows (private repo granted to the riding id → the advertisement
|
||||
flows; the same repo ungranted → the denial band + exit 1); no
|
||||
direct identity introspection needed, and the deny row doubles as
|
||||
the authorize-path witness. `None` can never occur post-auth and
|
||||
declines serving-path.
|
||||
- **Push semantics through the doubles**: the packless CAS path
|
||||
(alkgit ADR-020 §1) is the pack-free receive-pack row — commands +
|
||||
flush (caps NUL-attached on the first command line, `report-status`
|
||||
requested), no pack; the wire layer applies via
|
||||
`GitRefs::apply_updates` and writes the report (`unpack ok` /
|
||||
`ok <ref>`). The duplex discipline *drains the raw tail packless*
|
||||
— the row had to signal client-side EOF after the report flush
|
||||
(observed; the real client-eof shape), which is also why vanilla
|
||||
delete-pushes end cleanly. `GitPackIngest::prepare` never fires
|
||||
packless — asserted.
|
||||
- **Per-build matrix**: unchanged rows in `tests/dispatch_core.rs`
|
||||
(their observables hold — the config-driven decline keeps the
|
||||
failure-then-close shape in seam-less builds; unknown services keep
|
||||
failure-then-alive), docs/stamps updated for the new decision set;
|
||||
the git row's serving + grammar-decline rows live in the new
|
||||
`tests/git_mapping.rs` (empty module in non-git builds, compile-time
|
||||
feature isolation). `tests/observe.rs`'s git-row event row updated
|
||||
to the `seam-unconfigured` reason.
|
||||
- **Real-tool smoke posture** (recorded): the clone smoke (a real
|
||||
`git clone` of an unborn-HEAD repo over a TCP-mounted adapter — the
|
||||
same loopback server stack, the accept loop as the assembly's
|
||||
mount) **requires git ≥ 2.43 and ssh in the environment**;
|
||||
missing/older tooling is skipped *with a printed reason* —
|
||||
skipped-with-reason at most, never silently green. The empty-repo
|
||||
clone exercises the full chain (exec parse → dispatch → the seam
|
||||
advertisement → ls-refs → exit-status(0)) with zero pack bytes: the
|
||||
unborn-HEAD line is what real git 2.43's clone consumed (POC-3's
|
||||
OQ-19 rider shape), so the hand-rolled doubles stay noop-faithful.
|
||||
- **Verification**: `cargo test` (default build), `cargo test
|
||||
--features git --test git_mapping`, `cargo test --features session`,
|
||||
`cargo test --all-features`, `cargo clippy --all-targets --all-
|
||||
features -- -D warnings` ×2 (default + all-features), `cargo fmt
|
||||
--check`, `cargo doc --no-deps` — all green.
|
||||
Reference in new issue
Block a user